有没有人知道为什么java编译器不允许以下内容的明确答案?
class BaseClass {
public <T extends Number> T getNumber(){
return null;
}
}
class SubClass extends BaseClass{
@Override
public <T extends Integer> T getNumber(){
return null;
}
}
这导致编译器抱怨:
“SubClass类型的方法getNumber()必须覆盖超类方法”
现在,当我把它放到我的同事们时,有些人试图解释它会导致编译器混淆。然而,正如还指出的,在概念上类似的以下内容是可编译的。
class BaseClass<T extends Number> {
public T getNumber(){
return null;
}
}
class SubClass<T extends Integer> extends BaseClass<T>{
@Override
public T getNumber(){
return null;
}
}
如果子类调用超级实现,这可能会被滥用,但编译器会为此效果提供警告。我唯一的结论是,这是Sun公司的编译监督(不能让我自己说Oracle:-S)。
任何人都对这个有明确的答案吗?
答案 0 :(得分:4)
假设确实允许在派生类的类型参数上添加更多限制。
那么如果你的班级也有<T extends Number> void setNumber(T number)
方法怎么办?
BaseClass foo = new SubClass();
long longValue = 42;
foo.<Long>setNumber(longValue);
编译器接受上述内容,因为BaseClass.setNumber接受从Number
派生的任何类型参数。但实际实例只接受整数!
您可能会争辩说,如果type参数仅用于返回值,则应自动将其视为协变。但是编译器必须确保不以非协变的方式在方法体内使用type参数。
(在C# 4.0 this was actually solved中,但它涉及明确将您的类型参数标记为与out
和in
关键字的协变或逆变。编译器不能简单地允许这样做不改变语言。)
答案 1 :(得分:0)
我不太关注你的问题:
当我实现您的第一部分源代码并使用javac *.java
编译时,它编译得很好。但是,如果我更改了SubClass.getNumber()
方法来执行此操作...
/* (non-Javadoc)
* @see constraint.base.BaseClass#getNumber()
*/
@Override
public <T extends Number> T getNumber() {
// TODO Auto-generated method stub
return super.getNumber();
}
我收到以下错误:
SubClass.java:18: type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Number
return super.getNumber();
^
1 error
上面代码的原因是,通过调用super.getNumber()
,编译器没有任何推断类型T
的输入,因此它无法确定T
将返回super.getNumber()
。 {1}}因此,它无法满足SubClass.getNumber()
现在,为了从编译器"The method getNumber() of type SubClass must override a superclass method"
获得错误,您的BaseClass
应该是抽象以及它的getNumber()
方法。< / p>
对于您提供的第二段代码,子类实际上可以调用super.getNumber()
,因为编译器将知道(在编译时)SubClass的通用参数类型被推断为参数类型BaseClass
。
除此之外,我真的不知道你想问什么。
答案 2 :(得分:0)
@Wim Coenen提供了一个很好的答案。
这是一个小小的澄清。
如果这会编译,你会发生什么:
import java.math.BigInteger;
class BaseClass {
public <T extends Number> T getNumber(T n) {
System.out.println("Int value: " + n.intValue());
return n;
}
}
class SubClass extends BaseClass {
@Override
public <T extends BigInteger> T getNumber(T n) {
System.out.println("Int value: " + n.intValue());
// BigInteger specific!
System.out.println("Bit count: " + n.bitCount());
return n;
}
}
public class Main {
public static void main(String[] args) {
BaseClass sub = new SubClass();
// sub looks like a BaseClass...
// ...but since it's a SubClass it expects a BigInteger!
sub.getNumber(new Integer(5));
}
}
答案 3 :(得分:0)
因为这里没有协方差。协方差意味着'随'变化',它指的是作为包含类类型而变化的返回类型。这不是发生在这里。你的协方差中没有'co'。