2013-02-02 10 views
15

In Java ist es möglich, eine Schnittstelle zu definieren, die eine Methode hat, die ein Argument der implementierenden Klasse erhält?Java Generics: Interface-Methode, die Typ Argument der implementierenden Klasse

Schnittstelle:

public interface MyInterface { 
    public <T is/extends of the type of the implementing class> void method(T object); 
} 

Klasse:

public class A implements MyInterface { 

    public void method(A object) { 
     ... 
    } 

} 

Was ich vermeiden möchte, ist, dass eine Klasse MyInterface mit einer anderen Klasse wie selbst implementieren könnte.

So sollte dies nicht zulässig:

public class A implements MyInterface<B> { 

    public void method(B object) { 
     ... 
    } 

}  





Edit:

Ok ich versuche, auf eine andere Weise zu beschreiben, was ich erreichen will . Ich möchte mehrere Klassen haben, die eine Methode haben, die ein arg dieser Art von Klasse akzeptiert. So zusätzlich zu Klasse A können von oben sagen Theres eine andere Klasse B, die wie folgt aussieht:

public class B implements MyInterface { 

    public void method(B object) { 
     ... 
    } 

} 

welchen Stand die Klassen A und B gemeinsam haben, ist ein Verfahren, „Methode“ genannt, die eine arg von der Art des erhält Klasse selbst.

In meinem Projekt möchte ich Folgendes erreichen. Ich schreibe ein kleines Spiel und möchte eine Art Kollisionserkennung implementieren. im Grunde möchte ich dies tun, indem ich einige "intelligente" polymorphistische Aufrufe mache.

ich eine Schnittstelle ICollisionReceiver definiert, die wie folgt aussieht:

public interface ICollisionReceiver<T extends IShape> extends IShape { 

    public boolean collides(T t); 

} 

und ich definiert eine weitere Schnittstelle wie folgt aus:

public interface ICollisionChecker<T extends ICollisionChecker<T>> extends IShape { 

    public void addCollisionReceiver(ICollisionReceiver<T> receiver); 

    public void removeCollisionReceiver(ICollisionReceiver<T> receiver); 

} 

Jetzt zum Beispiel mein Player implementiert die Schnittstelle ICollisionReceiver als der Spieler erhält Kollisionen und behandelt sie. Dies sollte in allgemeiner Weise durchgeführt werden, so zum Beispiel I-Boxen und Kreis haben, jetzt die Spieler implementiert ICollisionReceiver < Box> und ICollisionReceiver < Kreis> so habe ich beide Methoden

@Override 
public boolean collides(final Box b) {   
    ... 
    return false; 
} 

und

@Override 
public boolean collides(final Circle c) {   
    ... 
    return false; 
} 

in meiner Box und Kreisklasse kann ich ICollisionReceivers registrieren und dann die folgenden in der Update-Methode, die ich tun:

boolean conti = true; 
    int i=0; 
    while(conti && i<collisionReceivers.size()) { 
     final ICollisionReceiver<Bonus> rec = collisionReceivers.get(i);    
     if(this.collidesWith(rec)) { 
      conti = rec.collides(this); 
     }    
     ++i; 
    } 

Dies prüft im Grunde, ob diese Box mit einem bestimmten Empfänger kollidiert und ruft dann die Methode collides() des Empfängers auf.

Jetzt ist der Punkt, ich möchte sicherstellen, dass beide Klassen Box und Kreis implementieren die ICollisionChecker-Schnittstelle nur mit ihrem eigenen Typ.

Ich kann dies explizit tun, indem Sie so etwas wie diese

public class Bonus extends AnimatedSprite implements ICollisionChecker<Bonus>... 

aber das ist nicht sehr befriedigend für mich tun ...

Sorry für den langen Post, ich hoffe das es deutlich macht.

+2

'public void-Methode (T-Objekt);' ist keine Option? denn wenn ich ehrlich bin, habe ich nicht verstanden, was du erreichen willst. – Zhedar

Antwort

20

Was Sie wollen, ist in Java nicht möglich ist, und ist nicht sinnvoll.

So sollte dies nicht zulässig:

Warum nicht? Welchen Zweck erfüllt das? Generika dürfen nicht willkürlich eingeschränkt werden. Generics sind nur nützlich, um Würfe zu eliminieren, die du sonst benötigen würdest, weil sie beweisen können, dass der Cast immer sicher ist.

Solange public class A implements MyInterface<B> typsicher ist, hat es keinen Sinn, eine willkürliche Einschränkung zu machen, die es verbietet.

Sie sollten einfach Ihre Schnittstelle als

public interface MyInterface<T> { 
    public void method(T object); 
} 

definieren und Sie können Ihre Klasse

public class A implements MyInterface<A> { 
    public void method(A object) { 
    } 
} 

definieren und wenn jemand anderes eine Klasse es

public class B implements MyInterface<A> { 
    public void method(A object) { 
    } 
} 

dann so sein definiert. Warum kümmert dich das? Welches Problem verursacht es?

+2

Ha, ich wusste, dass du es nach dem ersten Satz warst. Immer versuchen, das CRTP aus der Stadt zu laufen :) –

+1

ja es ist eine Einschränkung, was nicht die Absicht von Generika im Allgemeinen sein könnte, aber es bietet auch eine Art von Typsicherheit, da es sichergestellt hätte, dass ein Typ nur Kollisionen von behandelt dieser Typ selbst. Deshalb dachte/hoffte ich, dass dies möglich wäre. Trotzdem, vielen Dank für Ihre Antwort. – zersaegen

-1

Was möchten Sie ist wahrscheinlich so etwas tun:

public interface MyInterface <T extends A> { 
    public void method(T object) { 
     ... 
    } 
} 

public class A implements MyInterface<A_or_class_extending_A> 
{ ... } 

Ich hoffe, das half!

+0

Sie müssten auch die Deklaration der Schnittstelle als 'public interface MyInterface ' für Java angeben, um zu wissen, was 'T' ist. – Michael

+1

danke für Ihre Antwort. Leider erlaubt dies immer noch ClassImplementingMyInterface zu Klasse, die nicht A. – zersaegen

+0

Eigentlich ist dies nicht erforderlich - ich habe das generische für die Methode, nicht für die Klasse! – Pethor

4

Nun, das ist zumindest möglich:

public interface SelfImplementer<T extends SelfImplementer<T>> { 
    void method(T self); 
} 

Wie Sie sehen können, die Allgemeine Erklärung ein bisschen wie eine unendliche Rekursion aussieht und ich bin ziemlich sicher, dass, wenn Java nicht tat Typ Löschung haben wäre es - zum Glück alle Generika tatsächlich Objects sind nach Compiler mit ihnen umgegangen ist, so dass Sie diese

public class Impl implements SelfImplementer<Impl> { 
    @Override 
    public void method(Impl self) { 
     System.out.println("Hello!"); 
    } 
} 

und wie erwartet tun, um dieses

(?)
public static void main(String[] args) { 
    Impl impl = new Impl(); 
    impl.method(impl); 
} 

druckt

Hello! 
+2

Als eine Fußnote finde ich das völlig unsinnig und ich würde niemanden dazu ermutigen, dies tatsächlich zu benutzen. – Esko

+0

danke, aber ich wäre immer noch in der Lage, dies zu tun: öffentliche Klasse ImplBlubb implementiert SelfImplementer , so ImplBlubb würde die Schnittstelle mit Impl implementieren. Was ich will ist, dass es nur möglich ist, dass ImplBlubb die Schnittstelle mit ImplBlubb implementiert und dass Impl die Schnittstelle nur mit Impl implementieren kann ... – zersaegen

+0

Das macht nicht, was das OP will. Sie können immer noch 'öffentliche Klasse SomeOtherImpl implementiert SelfImplementer ' – newacct

Verwandte Themen