2015-05-13 10 views
37

Lassen Sie uns sagen, ich habe folgende Schnittstelle:Wie gelten weitere Einschränkungen für eine Schnittstellendeklaration in Java?

interface Mammal { 
    void marry(Mammal m); 
    Mammal giveBirthTo(); 
} 

Dies ist jedoch nicht ganz genau sagt, was ich will.

Offensichtlich kann ein Mensch weder einen Hund heiraten noch eine Katze zur Welt bringen. Wie kann ich diese Informationen in die Schnittstelle einbetten, so dass der Eingabetyp und der Ausgabetyp bei der Implementierung automatisch geändert werden können?

Antwort

47

Sie könnten Generika verwenden und Ihr Design ändern.

Etwas in den Zeilen:

interface Marriable<T extends Mammal> { 
    void marry(T sweetHalf); 
    T giveBirthTo(); 
} 

... wo Mammal Ihre Top-Schnittstelle oder eine abstrakte Klasse ist, und Human, Dog, Unicorn usw. erweitern/sie umzusetzen.

+2

Sollte die Schnittstelle nicht "Mammal" heißen? Es gibt keinen Grund, einen anderen hinzuzufügen. –

+1

@RafaelWinterhalter Nun, wie ich schon erwähnt habe, könnte man eine "Säugetier" -Schnittstelle oder abstrakte Klasse haben, die das oberste Tier in dieser bestimmten Vererbungskette abstrahiert. Die "Marriable" -Schnittstelle würde den Vertrag definieren, stattdessen eine Ihrer Spezies zu heiraten. – Mena

+0

Sie benötigen dazu nicht die 'Marriable'-Schnittstelle. Sie können einfach einen rekursiven Typ erstellen, wie in der Antwort vorgeschlagen, die ich gerade hinzugefügt habe. –

1

Generika. Versuchen Sie, mit

private static interface Race { 
} 

private static class Human implements Race {} 
private static class Canine implements Race {} 

private static interface Being<R extends Race> { 
    void marry(Being<R> other); 
    Being<R> giveBirthTo(); 
} 

private void tryMe() { 
    Being<Human> aHuman = new Being<Human>() { 

     @Override 
     public void marry(Being<Human> other) { 
     } 

     @Override 
     public Being<Human> giveBirthTo() { 
      return null; 
     } 
    }; 

    Being<Canine> aCanine = new Being<Canine>() { 

     @Override 
     public void marry(Being<Canine> other) { 
     } 

     @Override 
     public Being<Canine> giveBirthTo() { 
      return null; 
     } 
    }; 

    aHuman.marry(aCanine); // not possible 
} 
23

können Sie generify Ihre Schnittstelle einen rekursiven Variable:

interface Mammal<T extends Mammal<T>> { 
    void marry(T m); 
    T giveBirthTo(); 
} 

Auf diese Weise kann der Java-Compiler geben Sie eine bestimmte Gültigkeitsprüfungsstufe. Beachten Sie jedoch, dass dieser Ansatz weiterhin missbräuchlich ist. Zum Beispiel:

class Cat implements Mammal<Cat> { 
    @Override void marry(Cat cat) { ... } 
    @Override Cat giveBirthTo() { ... } 
} 

class Dog implements Mammal<Cat> { // implements wrong interface 
    @Override void marry(Cat cat) { ... } 
    @Override Cat giveBirthTo() { ... } 
} 

Der Compiler kann nur versichern, dass Sie die Mammal Schnittstelle von einigem Untertyp des gleichen Schnittstelle implementieren, aber nicht durch die besondere Klasse, die es implementiert. Dieser letztere Typ-Constraint kann nicht in der Java-Programmiersprache ausgedrückt werden.

+5

Für Ihr Googling-Vergnügen wird dies als * F-beschränkte Quantifizierung * bezeichnet. –

Verwandte Themen