【问题标题】:Calling ambiguously overloaded constructor in Java在 Java 中调用模糊重载的构造函数
【发布时间】:2011-04-17 08:31:42
【问题描述】:

我刚刚看到this C# question 并想知道,Java 中是否会发生类似的事情。它可以,与

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

电话

new A<Integer>(43);

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

【问题讨论】:

  • 看看Builder Design PatternFactory Pattern或类似的。使用上述构造函数将以 A a = new A(42); 之类的语句结尾,而这并不能说明 42 的实际含义。关于软件设计的更简洁的方法是A&lt;Integer&gt; a = A.createWithCapacity(42);。此外,这解决了您的歧义。
  • @coding.mof:我经常使用这些模式,但最后它们必须调用构造函数。但是,这可以很容易地解决,例如通过一个虚拟构造函数参数,因为没有人关心它的外观。我真的不记得我想要它是为了什么;也许我只是好奇。

标签: java generics constructor ambiguity


【解决方案1】:

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

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

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

Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);

【讨论】:

    【解决方案2】:

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

    在 Java 中,您的示例中的构造函数都不比另一个更具体,因为 TInteger 之间没有子类型关系。另见Reference is ambiguous with generics

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


    更多诡辩:

    如果&lt;T extends Integer&gt;,那么T确实是Integer的子类型,那么第二个构造函数比第一个构造函数更具体,将选择第二个构造函数。

    实际上 javac 不允许这两个构造函数共存。当前的 Java 语言规范中没有任何内容禁止它们,但是字节码中的限制迫使 javac 禁止它们。见Type Erasure and Overloading in Java: Why does this work?

    另外一点:如果&lt;T extends Integer&gt;,由于Integerfinal,T只能是Integer,所以Integer也必须是T的子类型,所以不是第二个构造函数比第一个更具体?

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

    【讨论】:

      【解决方案3】:

      确实,它是模棱两可的,因此如果您尝试new A&lt;Integer&gt;(new Integer(0)),则无法编译。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多