通过泛型方法覆盖非泛型方法

3

我希望在我的安卓项目中实现视图的自动化转换。因此,我想要重载

View findViewById(int id) {...}

通过方法

<T extends View> findViewById(int id) {...}

方法。但是Java编译不允许这样做,然而覆盖的方法不会与父类冲突,并且始终会返回视图对象或其子类的对象。我找到了一些信息,称Java不允许通过泛型方法覆盖非泛型方法,但我找不到为什么的解释。 http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ824 这个常见问题解答说这是不可能的,但我不明白为什么。例如我们有这样的类:
class Super { 
  public void set( Object arg) { ... } 
  public Object get() { ... } 
} 
class Sub extends Super {  
  public <S extends Number> void set( S arg) { ... } // overloads 
  public <S extends Number> S get() { ... } // overloads 
}

常见问题解答中提到应该使用重载进行编译,但我遇到了一个奇怪的问题: getter返回与我的findViewById相同的错误,但setter可以编译通过。

有人能解释一下这是为什么吗?为什么Java不允许用泛型覆盖非泛型,而setter可以编译通过,getter却不行呢?

我知道,我可以使用其他方法,例如:

<T extends View> findView(int id){
  return (T) findViewById(id);
}

或者

<T extends View> findView(int id, Class<T> clazz) {
  return clazz.cast(findViewById(id));
}

但我想了解,为什么要使用新的方法而不是覆盖原有方法?

//1
@Override
public View findViewById(int id) {
    return (View) super.findViewById(id);
}
//2
@Override
public <T extends View> T findViewById(int id) {
    return (T) super.findViewById(id);
}

因此,在编译时,1和2有什么区别?即使方法1比2更通用。
//3
@Override
public <T extends View> View findViewById(int id) {
    return (View) super.findViewById(id);
}

在我添加了以上方法后,我终于意识到,“T extends View”告诉编译器这不是没有“T extends View”的相同方法。因此,事实上,我创建了另一个新方法,但名称和参数相同,所以它无法编译。也许并不完全正确,但我理解的是类似于这样的情况。 感谢所有试图帮助我的人。

在签名中声明一个你不使用的类型参数是没有意义的。 - newacct
这很明显。我只是为了让大家理解而声明的。这是在我第三次编辑问题之后的事情 :) - Orest Savchak
1个回答

1

Sub中的set方法编译成功,因为您声明了一个名为set新方法,该方法可以接受任何扩展自Number的参数S。请注意,您没有在子类中覆盖超类中的set方法,而是重载了set方法。

对于get方法,您正在执行完全相同的操作,即重载get方法,但这次编译器会抱怨,因为它不是有效的,因为您只更改了方法的返回类型。例如:

public Integer get() {
    return null;
}

如果你想在同一个类或子类中声明另一个方法,只需更改该方法的返回类型即可,就像这样

public Double get() {
    return null;
}

那么编译器会抱怨“尝试使用不兼容的返回类型”,因为在Java中,返回类型不是方法签名的一部分。

如果您声明了set方法,您可以复制相同的问题。

public <S extends Number> void set(Object arg) {  }

在这种情况下,我们只需更改方法的返回类型,但为了有效地重载方法参数应该是不同的。
public <S extends Number> void set(String arg) {  } // overloads

将是一个有效的重载。


谢谢。最后我明白了,<T extends View> 就像是一个参数,它是另一种方法,所以它是重载而不是覆盖。但它具有相同的签名,所以它无法编译。 - Orest Savchak
您好,如果您觉得这篇文章有用,欢迎点赞。 - sol4me
我需要15点声望 :) 但是我会尽快完成。 - Orest Savchak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接