我刚刚发现您可以在单个类型参数绑定中指定多个类型(请参阅示例)。像任何新工具一样,我一直在尝试探索如何使用(和误用)的可能性。我精心设计了这个例子以帮助说明。
在下面的示例中,编译器给出了一个错误
dispatch(new AlphabetSoup());
方法调度(Demo.Soup)对于Demo类型
是不明确的
我可以理解这一点,因为任一方法签名都匹配。我的问题是如何在不改变方法的情况下解决这个问题?如果我想强制调用Soup版本,我可以向Soup转发:
dispatch((Soup)new AlphabetSoup())
但我不确定你是如何强制拨打其他版本的。有可能吗?
public class Demo {
interface HasA { public char getA(); }
interface HasB { public char getB(); }
interface HasC { public char getC(); }
interface Soup {
public void eat();
}
class Alphabet implements HasA, HasB, HasC {
public char getA() { return 'a'; }
public char getB() { return 'b'; }
public char getC() { return 'c'; }
}
class AlphabetSoup implements Soup, HasA, HasB, HasC {
public void eat() { System.out.println("Mmm Mmm Good!"); }
public char getA() { return 'a'; }
public char getB() { return 'b'; }
public char getC() { return 'c'; }
}
public void dispatch(Soup soup) {
System.out.println("Eating some soup...");
soup.eat();
}
public <T extends HasA & HasB & HasC> void dispatch(T letters) {
System.out.println("Reciting ABCs...");
System.out.println(letters.getA());
System.out.println(letters.getB());
System.out.println(letters.getC());
}
public void test() {
dispatch(new Alphabet());
dispatch(new AlphabetSoup());
}
public static void main(String[] args) {
new Demo().test();
}
}
- 编辑:刚刚了解到“多个有界类型参数正式称为”交叉类型“
答案 0 :(得分:11)
请注意,错误与泛型无关,如果使用接口并且类型是交集,则会得到相同的结果:
public class AA {
interface XX{};
interface YY{};
public void doSomething(XX x){}
public void doSomething(YY x){}
class XY implements XX,YY{
}
public void runner(){
doSomething(new XY());
}
}
你在“doSomething”中得到同样的错误,编译器无法解决歧义。你想解释为XX还是YY?你必须用演员表来指定它。 但是如果你有一个层次结构,比如“YY extends XX”和“XY implements YY”,编译器可以推断出正确的调用方法。
答案 1 :(得分:8)
编译器是正确的,可以帮助您避免混乱。
AlphaBetSoup是汤的子类型,也是HasA,HasB和HasC的子类型
因此,它符合两个版本的Dispatch
的账单由于Soup不是HasA,HasB或HasC的子类型,因此也不能说一个版本比另一个版本更具“特异性”。
因此,您将正确收到错误。
重载方法不应该含糊不清。如果您的类型混合了两种类型并且每种类型都有重载,请更改层次结构或消除过载。使用子类型和重载是错误的。
答案 2 :(得分:2)
让我用一个非常简单的程序解释一下:
下面的代码说明方法对于类型编译器错误是不明确的。
public class AmbiguousMethodOwner {
void ambiguousMethod(Comparable c){}
void ambiguousMethod(Serializable c){}
void test() {
ambiguousMethod("bar");
}
}
问题现在很明显:因为String实现了Comparable和 Serializable,编译器无法知道您打算调用哪种方法。
简单的演员表可以解决问题:
ambiguousMethod((比较) “栏中的”);
http://www.javaneverdie.com/java/the-method-is-ambiguous-for-the-type/
在我们的案例中,方法调度正在产生问题。见
class AlphabetSoup implements Soup, HasA, HasB, HasC
和
public void dispatch(Soup soup)
public <T extends HasA & HasB & HasC> void dispatch(T letters) {
现在,如果你调用dispatch(new AlphabetSoup());
编译器会混淆应该调用哪个版本的调度?
答案 3 :(得分:1)
请注意,您没有真正的问题,因为您有兴趣调用的方法因动态绑定而被调用。
运行dispatch((Soup) new AlphabetSoup());
会产生:
Reciting ABCs...
a
b
c
Eating some soup...
Mmm Mmm Good!
因此,由于基本的多态行为,已调用AlphabetSoup
方法。
答案 4 :(得分:1)
不是说你应该保留重载的dispatch
方法(因为这个原因我赞成了Uri),但你可以通过尝试强制调用泛型版本:
demo.<AlphabetSoup>dispatch(new AlphabetSoup());
或者用以下方式调用汤版:
demo.dispatch((Soup) new AlphabetSoup());
更好的解决方法是首先不要使用重载的dispatch
方法。
void dispatchSoup(Soup soup);
<T extends HasA & HasB & HasC> void dispatchLetters(T letters);