我刚才看到this C# question,想知道如果在Java中会发生类似的情况。它可以与在Java中调用含糊不清的重载构造函数
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通话
new A<Integer>(43);
是模糊的,我看不出有什么办法如何解决它。有没有?
我刚才看到this C# question,想知道如果在Java中会发生类似的情况。它可以与在Java中调用含糊不清的重载构造函数
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
通话
new A<Integer>(43);
是模糊的,我看不出有什么办法如何解决它。有没有?
是,参数化类型JLS3#4.5.2的成员可能会在正常类声明(#8.4.8)中排除的冲突中结束。想出很多这种例子很容易。
而在Java中,由于T
和Integer
之间没有子类型关系,所以在您的示例中,两个构造函数都没有比另一个更具体。另请参阅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>
,因为Integer
是final
,T只能是Integer
,所以Integer
也必须是T
一个亚型,因此不是第二构造也比第一次更具体?
第final
没有考虑子类型关系。实际上,有一天可以从Integer
中删除final
,Java甚至指定删除final
不会破坏二进制兼容性。
这表明清楚,并更多的感谢链接。 – maaartinus 2011-04-17 18:24:19
事实上,它是不明确的,所以如果你尝试new A<Integer>(new Integer(0))
,也不会编译。
您可以在施工期间下降仿制药(并抑制警告):
A<Integer> a = new A(42);
或较少优选使用反射(如你又不得不抑制警告)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
看看'Builder Design Pattern','Factory Pattern'或者类似的东西。使用上面提到的构造函数会以'A a = new A(42);'这样的语句结束,它不会告诉任何关于'42'实际是什么的东西。有关软件设计的更清晰的方法是'A a = A.createWithCapacity(42);'。此外,这解决了你的歧义。 –
2012-09-26 08:21:02
@ coding.mof:我使用这些模式很多,但最后他们不得不调用构造函数。然而,这可以很容易地解决,例如,由一个虚构的构造器参数,因为没有人关心它的样子。我真的不记得我想要什么;也许我只是好奇。 – maaartinus 2012-09-26 09:02:01