[英]Why does the compiler not enforce the return type value for a generic that extends an interface?
public class Test {
public static void main(String... args) {
ClassB clazzB1 = getClassA(); // compile error
ClassB clazzB2 = getInterfaceC1(); // compile error
ClassB clazzB3 = getInterfaceC2(); // no compile error
}
public static <T extends ClassA> T getClassA() {
return (T) new ClassA() {};
}
public static InterfaceC getInterfaceC1() {
return new InterfaceC() {};
}
public static <T extends InterfaceC> T getInterfaceC2() {
return (T) new InterfaceC() {};
}
private static abstract class ClassA {
}
private static class ClassB {
}
}
public interface InterfaceC {
}
Why does getInterfaceC2() not give a compile error when assigned to clazzB3?为什么 getInterfaceC2() 在分配给 clazzB3 时不会给出编译错误? It seems like it should and is something that I would like to have happen.
看起来它应该并且是我希望发生的事情。
You can always do:你总是可以这样做:
static class InterestingType extends ClassB implements InterfaceC {
}
And then have :然后有:
public static <T extends InterfaceC> T getInterfaceC2() {
return (T)new InterestingType();
}
As such calling:因此调用:
ClassB clazzB3 = getInterfaceC2();
would work.会工作。 In your case it is obvious to you that it will break, but the compiler can't prove that (easily).
在您的情况下,很明显它会中断,但编译器无法证明(很容易)。 As such, your example is allowed, but will fail at runtime.
因此,您的示例是允许的,但在运行时会失败。
EDIT编辑
The compiler looks at this:编译器看这个:
ClassB clazzB1 = getClassA();
and sees that getClassA()
returns a T
that is defined as T extends ClassA
, where ClassA
is a class .并看到
getClassA()
返回一个T
作为被定义T extends ClassA
,其中ClassA
是一类。 It also sees that this T
is assigned to ClassB
, where ClassB
is a class also .它还看到这个
T
被分配给ClassB
,其中ClassB
也是一个类。 So it has to create a certain type that will conform to both ClassA
and ClassB
, something like a theoretical :所以它必须创建一个符合
ClassA
和ClassB
的特定类型,类似于理论上的:
T extends ClassA & ClassB
but that is an impossible type, since no one can do ... extends ClassA, ClassB
(this is simply not allowed in java).但这是一种不可能的类型,因为没有人可以做到
... extends ClassA, ClassB
(这在 Java 中是不允许的)。 So the compiler fails.所以编译器失败了。 As a matter of fact if you do :
事实上,如果你这样做:
javac --debug=verboseResolution=all Test
you will see in the output, something like:您将在输出中看到,例如:
error: incompatible types: inference variable T has incompatible upper bounds ClassB,ClassA
错误:不兼容的类型:推理变量 T 的上限不兼容 ClassB,ClassA
On the other hand, when the compiler looks at this : ClassB clazzB3 = getInterfaceC2();
另一方面,当编译器查看此内容时:
ClassB clazzB3 = getInterfaceC2();
, it sees that getInterfaceC2()
returns: ,它看到
getInterfaceC2()
返回:
T extends InterfaceC
and the result is assigned to ClassB
, so it ends up with may be this type:并将结果分配给
ClassB
,因此最终可能是这种类型:
T extends ClassB & InterfaceC
which is perfectly valid.这是完全有效的。 There can be such a type.
可以有这样的类型。 I've shown you that you can create one as
InterestingType
, but as Holger pointed out, you could pass such a theoretical type yourself, via:我已经向您展示了您可以创建一个
InterestingType
,但正如 Holger 指出的那样,您可以通过以下方式自己传递这样一个理论类型:
ClassB clazzB3 = Test.<InterestingType>getInterfaceC2();
this is called specifying a "type witness".这称为指定“类型见证”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.