我刚刚看到this C# question并想知道,如果在Java中发生类似的事情。它可以,
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
电话
new A<Integer>(43);
含糊不清,我认为无法解决问题。有没有?
答案 0 :(得分:3)
您可以在构建期间删除泛型(并禁止警告):
A<Integer> a = new A(42);
或者,不太喜欢使用反射(你必须再次禁止警告)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
答案 1 :(得分:2)
确实,它含糊不清,如果你尝试new A<Integer>(new Integer(0))
,也不会编译。
答案 2 :(得分:2)
是的,参数化类型JLS3#4.5.2的成员可能会在正常的类声明(#8.4.8)中排除冲突。很容易想出很多这样的例子。
在Java中,示例中的构造函数都不比其他构造函数更具体,因为T
和Integer
之间没有子类型关系。另见Reference is ambiguous with generics
如果方法重载会产生这种歧义,我们通常可以选择使用不同的方法名称。但是构造函数不能重命名。
更多诡辩:
如果<T extends Integer>
,那么T
确实是Integer
的子类型,那么第二个构造函数比第一个更具体,第二个构造函数将被选中。
实际上javac不允许这两个构造函数共存。当前Java语言规范中没有任何内容禁止它们,但字节码中的限制迫使javac禁止它们。见Type Erasure and Overloading in Java: Why does this work?
另一点:如果<T extends Integer>
,Integer
为final
,则T只能为Integer
,因此Integer
也必须是T
的子类型1}},因此不是第二个构造函数也比第一个更具体吗?
没有。在子类型关系中不考虑final
。实际上有一天可以从final
删除Integer
,Java甚至指定删除final
不会破坏二进制兼容性。