我刚刚发现您可以在单个类型参数绑定中指定多个类型(请参阅示例).像任何新工具一样,我一直在尝试探索如何使用(和误用)的可能性.我精心设计了这个例子以帮助说明.
在下面的示例中,编译器给出了一个错误
dispatch(new AlphabetSoup());
对于Demo类型,方法dispatch(Demo.Soup)是不明确的
我能理解这一点,因为任何方法签名都匹配.我的问题是如何在不改变方法的情况下解决这个问题?如果我想要强制调用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();
}
}
Run Code Online (Sandbox Code Playgroud)
- 编辑:刚刚了解到"多个有界类型参数被正式称为"交叉类型"
GCl*_*unt 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());
}
}
Run Code Online (Sandbox Code Playgroud)
你在"doSomething"中得到同样的错误,编译器无法解决歧义.你想解释为XX还是YY?你必须用演员表来指定它.但是如果你有一个层次结构,比如"YY extends XX"和"XY implements YY",编译器可以推断出正确的调用方法.
编译器是正确的,可以帮助您避免混乱.
AlphaBetSoup是汤的子类型,也是HasA,HasB和HasC的子类型
因此,它符合两个版本的Dispatch的账单
由于Soup不是HasA,HasB或HasC的子类型,因此也不能说一个版本比另一个版本更具"特异性".
因此,您将正确地得到错误.
重载方法不应该含糊不清.如果您的类型混合了两种类型并且每种类型都有重载,请更改层次结构或消除过载.使用子类型和重载是错误的.
让我用一个非常简单的程序来解释这一点:
下面的代码说明了该方法因类型编译器错误而不明确的原因。
public class AmbiguousMethodOwner {
void ambiguousMethod(Comparable c){}
void ambiguousMethod(Serializable c){}
void test() {
ambiguousMethod("bar");
}
}
Run Code Online (Sandbox Code Playgroud)
现在的问题很明显:由于String同时实现了Comparable和Serialized,编译器无法知道你打算调用哪个方法。
一个简单的强制转换就可以解决这个问题:
ambigitudeMethod((可比较)“酒吧”);
http://www.javaneverdie.com/java/the-method-is-ambiguously-for-the-type/
在我们的例子中,方法调度正在产生问题。看
class AlphabetSoup implements Soup, HasA, HasB, HasC
Run Code Online (Sandbox Code Playgroud)
和
public void dispatch(Soup soup)
public <T extends HasA & HasB & HasC> void dispatch(T letters) {
Run Code Online (Sandbox Code Playgroud)
现在,如果您调用dispatch(new AlphabetSoup());编译器,则会对应该调用哪个版本的调度感到困惑?
请注意,您没有真正的问题,因为您有兴趣调用的方法已经由于动态绑定而被调用。
运行dispatch((Soup) new AlphabetSoup());产量:
Reciting ABCs...
a
b
c
Eating some soup...
Mmm Mmm Good!
Run Code Online (Sandbox Code Playgroud)
因此,AlphabetSoup由于基本的多态行为,该方法已经被调用。