如何解决由 Java 泛型中的交集类型引起的歧义方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/815771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I resolve ambiguous methods caused by intersection types in Java generics?
提问by Mark Renouf
I just recently discovered that you can specify multiple types in a single type parameter bound (see example). Like any new tool, I've been trying to explore the possibilities of how this can be used (and misused). I crafted this example to help illustrate.
我最近才发现您可以在单个类型参数绑定中指定多种类型(参见示例)。像任何新工具一样,我一直在尝试探索如何使用(和误用)它的可能性。我精心制作了这个例子来帮助说明。
On the sample below, the compiler is giving me an error
在下面的示例中,编译器给了我一个错误
dispatch(new AlphabetSoup());
The method dispatch(Demo.Soup) is ambiguous for the type Demo
调度(新字母汤());
方法 dispatch(Demo.Soup) 对于 Demo 类型不明确
I can understand this because either method signature matches. My question is how could this be resolved without changing the methods? If I wanted force a call to the Soup version I could downcast to Soup:
我可以理解这一点,因为任一方法签名都匹配。我的问题是如何在不改变方法的情况下解决这个问题?如果我想强制调用 Soup 版本,我可以向 Soup 垂头丧气:
dispatch((Soup) new AlphabetSoup())
dispatch((Soup) new AlphabetSoup())
But I'm unsure how you'd force a call to the other version. Is it possible?
但我不确定你会如何强制调用另一个版本。是否可以?
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();
}
}
-- Edit: Just learned that "multiple bounded type parameters are formally referred to as "Intersection Types"
-- 编辑:刚刚了解到“多个有界类型参数正式称为“交集类型”
回答by Yuval Adam
Note that you do not have a real problem, as the methods you are interested in calling are already called due to dynamic binding.
请注意,您没有真正的问题,因为由于动态绑定,您有兴趣调用的方法已经被调用。
Running dispatch((Soup) new AlphabetSoup());
yields:
运行dispatch((Soup) new AlphabetSoup());
产量:
Reciting ABCs...
a
b
c
Eating some soup...
Mmm Mmm Good!
Hence, the AlphabetSoup
method are already called due to basic polymorphic behavior.
因此,AlphabetSoup
由于基本的多态行为,该方法已经被调用。
回答by Uri
The compiler is right, and saves you from a mess.
编译器是对的,可以让你免于一团糟。
AlphaBetSoup is a subtype of soup and also a subtype of HasA, HasB, and HasC
AlphaBetSoup 是汤的亚型,也是 HasA、HasB 和 HasC 的亚型
Therefore, it fits the bill for both versions of Dispatch
因此,它适合两个版本的 Dispatch
Since Soup is not a subtype of HasA, HasB, or HasC, it also can't say that one version is more "specific" than the other.
由于 Soup 不是 HasA、HasB 或 HasC 的子类型,因此也不能说一个版本比另一个版本更“具体”。
Therefore you'll get the error correctly.
因此你会正确地得到错误。
Overloaded method should not be ambiguous. If you have a type that mixes both types and you had an overload for each, change your hierarchy or get rid of an overload. It's wrong use of subtyping and overloading.
重载方法不应该有歧义。如果您有一个混合了这两种类型的类型,并且每种类型都有一个重载,请更改您的层次结构或摆脱重载。错误地使用子类型和重载。
回答by GClaramunt
Note that the error is not related to generics, you get the same result if you use interfaces and a type is the intersection:
请注意,错误与泛型无关,如果使用接口并且类型是交集,则会得到相同的结果:
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());
}
}
You get the same error in "doSomething", the compiler cannot resolve the ambiguity. Do you want to interpret as XX or as YY? You have to specify it with a cast. But if you have a hierarchy, like "YY extends XX" and "XY implements YY", the compiler can infer the correct method to call.
您在“doSomething”中遇到相同的错误,编译器无法解决歧义。你想解释为XX还是YY?你必须用演员表来指定它。但是如果你有一个层次结构,比如“YY扩展XX”和“XY实现YY”,编译器可以推断出正确的调用方法。
回答by Steve Reed
Not that you should keep the overloaded dispatch
method (I upvoted Uri for that reason), but you can force the generic version to be called by trying:
并不是说您应该保留重载的dispatch
方法(因此我赞成 Uri),但是您可以通过尝试强制调用通用版本:
demo.<AlphabetSoup>dispatch(new AlphabetSoup());
or call the soup version with:
或调用汤版本:
demo.dispatch((Soup) new AlphabetSoup());
The better way around this, though, is to not have the overloaded dispatch
method in the first place.
不过,更好的解决方法是首先不要使用重载dispatch
方法。
void dispatchSoup(Soup soup);
<T extends HasA & HasB & HasC> void dispatchLetters(T letters);
回答by AZ_
Let me explain this with a very simple program:
让我用一个非常简单的程序来解释这一点:
Code below illustrated couse of The method is ambiguous for the type compiler error.
下面的代码说明了该方法对于类型编译器错误的歧义。
public class AmbiguousMethodOwner {
void ambiguousMethod(Comparable c){}
void ambiguousMethod(Serializable c){}
void test() {
ambiguousMethod("bar");
}
}
The problem now is obvious: since String implements both Comparable and Serializable, the compiler cannot know which method you intend to call.
现在的问题很明显:由于 String 实现了 Comparable 和 Serializable,编译器无法知道您打算调用哪个方法。
A simple cast will solve the problem:
一个简单的演员将解决这个问题:
ambiguousMethod((Comparable)"bar");
ambiguousMethod((Comparable)"bar");
http://www.javaneverdie.com/java/the-method-is-ambiguous-for-the-type/
http://www.javaneverdie.com/java/the-method-is-ambiguous-for-the-type/
In our case method dispatch is creating problem. See
在我们的例子中,方法调度正在产生问题。看
class AlphabetSoup implements Soup, HasA, HasB, HasC
and
和
public void dispatch(Soup soup)
public <T extends HasA & HasB & HasC> void dispatch(T letters) {
now if you call dispatch(new AlphabetSoup());
compiler would be confused as to which version of dispatch should be called ?
现在,如果你调用dispatch(new AlphabetSoup());
编译器会混淆应该调用哪个版本的调度?