2

我刚刚看到这个 C# 问题,想知道在 Java 中是否会发生类似的事情。它可以,与

class A<T> {
    A(Integer o) {...}
    A(T o) {...}
}

通话

new A<Integer>(43);

是模棱两可的,我看不出如何解决它。有没有?

4

3 回答 3

3

您可以在构造过程中删除泛型(并抑制警告):

A<Integer> a = new A(42);

或者,不太推荐使用反射(你必须再次抑制警告)

Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
于 2011-04-17T09:02:05.333 回答
2

确实,它是模棱两可的,因此如果您尝试new A<Integer>(new Integer(0)).

于 2011-04-17T08:36:14.813 回答
2

是的,参数化类型JLS3#4.5.2的成员最终可能会出现在普通类声明 (#8.4.8) 中被排除的冲突。很容易想出很多这样的例子。

T在 Java 中,您的示例中的构造函数都没有比另一个更具体,因为and之间没有子类型关系Integer。另见参考与泛型不明确

如果方法重载造成这种歧义,我们通常可以选择使用不同的方法名称。但构造函数不能重命名。


更多诡辩:

如果<T extends Integer>, 那么确实T是 的子类型Integer,那么第二个构造函数比第一个构造函数更具体,并且将选择第二个构造函数。

实际上 javac 不允许这两个构造函数共存。当前的 Java 语言规范中没有任何内容禁止它们,但是字节码中的限制迫使 javac 禁止它们。请参阅Java 中的类型擦除和重载:为什么会这样?

另一点:如果<T extends Integer>,since Integeris final, T 只能是Integer, soInteger也必须是 的子类型T,因此第二个构造函数不是也比第一个更具体吗?

final考虑在子类型关系中。确实有可能finalInteger某一天开始掉线,Java 甚至指定删除final不会破坏二进制兼容性。

于 2011-04-17T17:02:50.440 回答