我有以下通用类:
class Or<A,B>
{
Or (A a) {}
Or (B b) {}
}
当我尝试编译它时,为什么会出现以下错误:
Or(A) is already defined in Or Or (B b) ^我认为两个构造函数共享相同的签名,尽管它们具有不同的泛型类型参数。为什么?如何解决这个问题?
更新:
我现在理解了问题。编译器需要一种区分两种类型的方法。对于我的用例添加这样的约束是可以的。所以我想再提一个问题:
如何指定A和B这两种类型可以是任何但不能不同?
我有以下通用类:
class Or<A,B>
{
Or (A a) {}
Or (B b) {}
}
Or(A) is already defined in Or Or (B b) ^我认为两个构造函数共享相同的签名,尽管它们具有不同的泛型类型参数。为什么?如何解决这个问题?
我认为这两个构造函数具有不同的泛型类型参数,但它们共享相同的签名。
确实如此。签名为
Or(Object o);
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(...);
}
A
和 B
那样优雅。 - Sergey Kalinichenko方法Or(A)的类型擦除与类型Or中的另一个方法Or(Object)相同
如果对泛型进行限制,它将编译通过:
class Or<A extends String, B extends Integer> { Or(A a) {}
Or(B b) {} }
这是由于type erasure的原因:编译时泛型将被替换为Object类型,因此您的方法具有相同的签名。作为一个解决方法,您可以选择缩小A和B的类型范围:
public class Test<A extends String, B extends Number> {
public Test(A arg){
}
public Test(B arg){
}
}
由于在运行时无法识别它们的类型,因此这些构造函数将被视为具有相同的签名。
如果可能的话,请尝试对至少一个类型参数指定边界。
class Or<A extends Number,B>
{
Or (A a) {}
Or (B b) {}
}
考虑一下,应该调用哪个构造函数?
Or<Integer,Integer> o = new Or<>(5);
你的问题实际上来自于类型擦除,编译后你的代码会变成这样:
class Or
{
Or (Object a) {}
Or (Object b) {}
}
这是不合法的,因为泛型在运行时被擦除了(这就是类型擦除)。你的两个方法都会有一个Or(Object)
的原型。
唯一的解决方案就是有一个OrA()
和 OrB()
方法 -- 或者彻底检查你的类。