2009-05-02 3 views
8

Ich habe vor kurzem entdeckt, dass Sie mehrere Typen in einer einzelnen Typparameterbindung angeben können (siehe Beispiel). Wie jedes neue Werkzeug habe ich versucht, die Möglichkeiten zu erkunden, wie dies genutzt (und missbraucht) werden kann. Ich habe dieses Beispiel zur Veranschaulichung erstellt.Wie behebe ich mehrdeutige Methoden, die durch Schnitttypen in Java-Generics verursacht werden?

auf der Probe unten wird der Compiler mir einen Fehler geben

dispatch (neue AlphabetSoup());

Die Methode dispatch (Demo.Soup) ist nicht eindeutig für den Typ Demo

Ich kann das verstehen, weil entweder Methodensignatur übereinstimmt. Meine Frage ist, wie kann das gelöst werden, ohne die Methoden zu ändern? Wenn ich wollte einen Aufruf an die Version Suppe zwingen, ich Suppe niedergeschlagenen könnte:

Versand ((Suppe) neue AlphabetSoup())

Aber ich bin nicht sicher, wie Sie einen Anruf zwingen würden zu der anderen Version. Ist es möglich?

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: gerade gelernt, dass „mehrere beschränkten Typs Parameter formal bezeichnet werden als‚Kreuzungstypen‘

+0

Ich glaube, die einzige Möglichkeit, die andere Versandmethode aufzurufen, ist die Verwendung von Reflektion. –

Antwort

1

Beachten Sie, dass Sie nicht über ein echtes Problem, wie die Methoden, die Sie daran interessiert sind, Gespräche bereits aufgrund dynamischer Bindung genannt

dispatch((Soup) new AlphabetSoup()); Ausbeuten Laufen.

Reciting ABCs... 
a 
b 
c 
Eating some soup... 
Mmm Mmm Good! 

Daher ist die AlphabetSoup Methode werden bereits aufgrund von polymorphem Grundverhalten genannt.

6

Der Compiler ist richtig und rettet Sie vor Unordnung.

AlphaBetSoup ein Subtyp der Suppe ist und auch ein Subtyp von Hasa, HASB und HASC

Daher passt die Rechnung für beide Versionen von Versand

Da Suppe ist kein Subtyp von Hasa, HASB oder HasC, es kann auch nicht sagen, dass eine Version "spezifischer" als die andere ist.

Daher erhalten Sie den Fehler richtig.

Überladene Methode sollte nicht mehrdeutig sein. Wenn Sie einen Typ haben, der beide Typen mischt und Sie für jede eine Überladung hatten, ändern Sie Ihre Hierarchie oder entfernen Sie eine Überladung. Es ist falsch, Subtyping und Überladung zu verwenden.

+0

ausgezeichnete Erklärung :) +1 –

10

Beachten Sie, dass der Fehler nicht auf Generika verwendet ist, das gleiche Ergebnis erhalten, wenn Sie Schnittstellen verwenden und ein Typ ist der Schnittpunkt:

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()); 
    } 
} 

Sie erhalten die gleichen Fehler in „doSomething“, der Compiler kann nicht Lösen Sie die Mehrdeutigkeit. Möchten Sie als XX oder als YY interpretieren? Sie müssen es mit einer Besetzung angeben. Aber wenn Sie eine Hierarchie haben, wie "YY erweitert XX" und "XY implementiert YY", kann der Compiler die richtige Methode zum Aufrufen ableiten.

mit
demo.<AlphabetSoup>dispatch(new AlphabetSoup()); 

oder rufen Sie die Suppe Version:

1

Nicht, dass Sie die überladene dispatch Methode halten sollte (I upvoted Uri aus diesem Grund), aber Sie können die generische Version zwingen, indem man versucht, aufgerufen werden

demo.dispatch((Soup) new AlphabetSoup()); 

Der bessere Weg ist jedoch, die überladene dispatch Methode in erster Linie nicht zu haben.

void dispatchSoup(Soup soup); 
<T extends HasA & HasB & HasC> void dispatchLetters(T letters); 
2

Lassen Sie mich diese einfaches Programm mit einem sehr erklären:

-Code unten dargestellt couse des Verfahrens ist für den Typ-Compiler-Fehler nicht eindeutig.

public class AmbiguousMethodOwner { 
      void ambiguousMethod(Comparable c){} 
      void ambiguousMethod(Serializable c){} 
      void test() { 
        ambiguousMethod("bar"); 
      } 
    } 

Das Problem ist jetzt klar: da String beide Vergleichbare implementiert und Serializable, der Compiler nicht, welche Methode Sie beabsichtigen, zu nennen wissen können.

Ein einfaches Guss das Problem lösen:

ambiguousMethod ((Vergleichbar) "bar");

http://www.javaneverdie.com/java/the-method-is-ambiguous-for-the-type/

In unserem Fall ist die Schaffung Verfahren Dispatch Problem. Siehe

class AlphabetSoup implements Soup, HasA, HasB, HasC 

und

public void dispatch(Soup soup) 
public <T extends HasA & HasB & HasC> void dispatch(T letters) { 

jetzt, wenn Sie dispatch(new AlphabetSoup()); Compiler verwechselt würden nennen darüber, welche Version der Versendung sollte genannt werden?

Verwandte Themen