在 Java 中调用模糊重载的构造函数

发布于 2024-11-01 20:36:03 字数 354 浏览 0 评论 0原文

我刚刚看到 这个 C# 问题 并想知道,如果Java 中也可能发生类似的事情。它可以,因为

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

调用

new A<Integer>(43);

不明确,我看不出如何解决它。有吗?

I just saw this C# question and wondered, if something similar could happen in Java. It can, with

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

the call

new A<Integer>(43);

is ambiguous and I see no way how to resolve it. Is there any?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笑饮青盏花 2024-11-08 20:36:03

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

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

或者,不太优选使用反射(您再次必须抑制警告)

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

You can drop the generics during construction (and suppress a warning):

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

or, less preferably use reflection (where again you'd have to suppress warnings)

Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
别念他 2024-11-08 20:36:03

是的,参数化类型的成员 JLS3#4.5 .2 可能会导致普通类声明中排除的冲突(#8.4.8)。很容易想出很多这样的例子。

在 Java 中,示例中的两个构造函数都没有比另一个更具体,因为 TInteger 之间没有子类型关系。另请参阅引用与泛型不明确

如果方法重载会产生这种情况为了避免歧义,我们通常可以选择使用不同的方法名称。但构造函数不能重命名。


更多诡辩:

如果 ,那么 T 确实是 Integer 的子类型,那么第二个构造函数比第一个,第二个将被选择。

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

还有一点:如果,因为Integerfinal,所以T只能是Integer,因此 Integer 也必须是 T 的子类型,因此第二个构造函数不是也比第一个构造函数更具体吗?

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

Yes, members of a parameterized type JLS3#4.5.2 can end up in conflicts that are precluded in a normal class declaration(#8.4.8). It's pretty easy to come up with many examples of this kind.

And in Java, neither constructor in your example is more specific than the other, because there is no subtyping relation between T and Integer. see also Reference is ambiguous with generics

If method overloading creates this kind of ambiguity, we can usually choose to use distinct method names. But constructors cannot be renamed.


More sophistries:

If <T extends Integer>, then indeed T is a subtype of Integer, then the 2nd constructor is more specific than the 1st one, and the 2nd one would be chosen.

Actually javac wouldn't allow these two constructors to co-exist. There is nothing in the current Java language specification that forbids them, but a limitation in the bytecode forces javac to forbid them. see Type Erasure and Overloading in Java: Why does this work?

Another point: If <T extends Integer>, since Integer is final, T can only be Integer, so Integer must also be a subtype of T, therefore isn't the 2nd constructor also more specific than the 1st?

No. final isn't considered in subtyping relations. It is actually possible to drop final from Integer one day, and Java even specifies that removing final does not break binary compatibility.

负佳期 2024-11-08 20:36:03

事实上,它是不明确的,因此如果您尝试 new A(new Integer(0)) 则无法编译。

Indeed, it is ambiguous, and so doesn't compile if you try new A<Integer>(new Integer(0)).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文