2011-04-17 29 views
2

我刚才看到this C# question,想知道如果在Java中会发生类似的情况。它可以与在Java中调用含糊不清的重载构造函数

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

通话

new A<Integer>(43); 

是模糊的,我看不出有什么办法如何解决它。有没有?

+0

看看'Builder Design Pattern','Factory Pattern'或者类似的东西。使用上面提到的构造函数会以'A a = new A(42);'这样的语句结束,它不会告诉任何关于'42'实际是什么的东西。有关软件设计的更清晰的方法是'A a = A.createWithCapacity(42);'。此外,这解决了你的歧义。 – 2012-09-26 08:21:02

+0

@ coding.mof:我使用这些模式很多,但最后他们不得不调用构造函数。然而,这可以很容易地解决,例如,由一个虚构的构造器参数,因为没有人关心它的样子。我真的不记得我想要什么;也许我只是好奇。 – maaartinus 2012-09-26 09:02:01

回答

2

是,参数化类型JLS3#4.5.2的成员可能会在正常类声明(#8.4.8)中排除的冲突中结束。想出很多这种例子很容易。

而在Java中,由于TInteger之间没有子类型关系,所以在您的示例中,两个构造函数都没有比另一个更具体。另请参阅Reference is ambiguous with generics

如果方法重载创建了这种模糊性,我们通常可以选择使用不同的方法名称。但构造函数不能被重命名。


更多的诡辩:

如果<T extends Integer>,那么确实TInteger一个亚型,那么第二个构造函数是比第一一个更具体,而第二人会选择。

其实javac不会允许这两个构造函数共存。目前的Java语言规范中没有任何东西禁止它们,但字节码中的限制迫使javac禁止它们。看到Type Erasure and Overloading in Java: Why does this work?

另外一点:如果<T extends Integer>,因为Integerfinal,T只能是Integer,所以Integer也必须是T一个亚型,因此不是第二构造也比第一次更具体?

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

+0

这表明清楚,并更多的感谢链接。 – maaartinus 2011-04-17 18:24:19

2

事实上,它是不明确的,所以如果你尝试new A<Integer>(new Integer(0)),也不会编译。

3

您可以在施工期间下降仿制药(并抑制警告):

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

或较少优选使用反射(如你又不得不抑制警告)

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