我刚刚看到这个 C# 问题,想知道在 Java 中是否会发生类似的事情。它可以,与
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通话
new A<Integer>(43);
是模棱两可的,我看不出如何解决它。有没有?
我刚刚看到这个 C# 问题,想知道在 Java 中是否会发生类似的事情。它可以,与
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通话
new A<Integer>(43);
是模棱两可的,我看不出如何解决它。有没有?
您可以在构造过程中删除泛型(并抑制警告):
A<Integer> a = new A(42);
或者,不太推荐使用反射(你必须再次抑制警告)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
确实,它是模棱两可的,因此如果您尝试new A<Integer>(new Integer(0))
.
是的,参数化类型JLS3#4.5.2的成员最终可能会出现在普通类声明 (#8.4.8) 中被排除的冲突。很容易想出很多这样的例子。
T
在 Java 中,您的示例中的构造函数都没有比另一个更具体,因为and之间没有子类型关系Integer
。另见参考与泛型不明确
如果方法重载造成这种歧义,我们通常可以选择使用不同的方法名称。但构造函数不能重命名。
更多诡辩:
如果<T extends Integer>
, 那么确实T
是 的子类型Integer
,那么第二个构造函数比第一个构造函数更具体,并且将选择第二个构造函数。
实际上 javac 不允许这两个构造函数共存。当前的 Java 语言规范中没有任何内容禁止它们,但是字节码中的限制迫使 javac 禁止它们。请参阅Java 中的类型擦除和重载:为什么会这样?
另一点:如果<T extends Integer>
,since Integer
is final
, T 只能是Integer
, soInteger
也必须是 的子类型T
,因此第二个构造函数不是也比第一个更具体吗?
不final
考虑在子类型关系中。确实有可能final
从Integer
某一天开始掉线,Java 甚至指定删除final
不会破坏二进制兼容性。