在Java中调用含糊不清的重载构造函数

时间:2011-04-17 08:31:43

标签: java generics constructor ambiguity

我刚刚看到this C# question并想知道,如果在Java中发生类似的事情。它可以,

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

电话

new A<Integer>(43);

含糊不清,我认为无法解决问题。有没有?

3 个答案:

答案 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中,示例中的构造函数都不比其他构造函数更具体,因为TInteger之间没有子类型关系。另见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>Integerfinal,则T只能为Integer,因此Integer也必须是T的子类型1}},因此不是第二个构造函数也比第一个更具体吗?

没有。在子类型关系中不考虑final。实际上有一天可以从final删除Integer,Java甚至指定删除final不会破坏二进制兼容性。