如何解决由 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:47:41  来源:igfitidea点击:

How do I resolve ambiguous methods caused by intersection types in Java generics?

javagenerics

提问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 AlphabetSoupmethod 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 dispatchmethod (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 dispatchmethod 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());编译器会混淆应该调用哪个版本的调度?