我有以下通用类:
class Or<A,B>
{
Or (A a) {}
Or (B b) {}
}
为什么在尝试编译时会出现以下错误:
Or(A) is already defined in Or Or (B b) ^
在我看来,两个构造函数共享相同的签名,尽管它们具有不同的泛型类型参数。为什么?以及如何解决这个问题?
更新
我现在明白了这个问题。编译器需要一种方法来区分这两种类型。添加这样的约束对我的用例来说是可以的。所以我想补充一个问题:
如何指定A和B这两种类型可以是不同的?
答案 0 :(得分:8)
在我看来,两个构造函数共享相同的签名,尽管它们具有不同的泛型类型参数。
他们这样做。签名是
Or(Object o);
为什么?
由于Java中泛型的type erasure实现:对泛型类型的引用在使用它们的所有上下文中都被转换为System.Object
;泛型类型只有编译器知道。
如何解决这个问题?
不幸的是,您无法在构造函数中轻松解决此问题。您可以使用工厂方法替换重载的构造函数,并提供不同的名称,例如OrWithA
和OrWithB
:
// Hide the constructor
private Or(...) {
...
}
// Publish factory methods
public static <X> Or OrWithA(X a) {
return new Or(...);
}
public static <X> Or OrWithB(X a) {
return new Or(...);
}
答案 1 :(得分:2)
他们就是这么做的。这是仿制药的本质;它们只提供在编译时使用的合成糖。没有办法围绕它。
(确认问题评论)这称为类型擦除:见http://en.wikipedia.org/wiki/Type_erasure
答案 2 :(得分:2)
这是因为A或B可以是任何东西,它们可以是相同的,因为泛型只是为了编译时间。在运行时,它们因类型擦除而丢失
答案 3 :(得分:2)
这是由于type erasure。 Eclipse编译器提供了更详细的错误:
Method Or(A) has the same erasure Or(Object) as another method in type Or
如果你对泛型应用限制,它编译得很好:
class Or<A extends String, B extends Integer> { Or(A a) {} Or(B b) {} }
答案 4 :(得分:1)
换句话说:你有两种类型,A和B,并且两者都不知道。所以一个完全未知的类型和另一个类型一样好。应该如何调度构造函数调用?
答案 5 :(得分:0)
这不合法,因为泛型在运行时被丢弃(这是类型擦除)。您的两种方法都有Or(Object)
的原型。
唯一的解决方案是使用OrA()
和OrB()
方法 - 或完全审核您的课程。
答案 6 :(得分:0)
这是因为type erasure:generics在编译时被Object类型替换,因此您的方法具有相同的签名。作为一个工作单,您可以选择缩小A和B的类型:
public class Test<A extends String, B extends Number> {
public Test(A arg){
}
public Test(B arg){
}
}
答案 7 :(得分:0)
这些构造函数将被视为具有相同的签名,因为它们的类型无法在运行时识别。
如果可能,请尝试在至少一个类型参数上指定边界。
class Or<A extends Number,B>
{
Or (A a) {}
Or (B b) {}
}
答案 8 :(得分:0)
考虑一下,要调用哪个构造函数?
Or<Integer,Integer> o = new Or<>(5);
您的问题确实来自类型删除,它会在编译后使您的代码看起来像这样:
class Or
{
Or (Object a) {}
Or (Object b) {}
}