11 Stimmen

Generischer Java-Typ

Wenn ich eine Schnittstelle habe

public interface Foo<T> {
    T someMethod();
}

Gibt es eine Möglichkeit, um sicherzustellen, dass, wenn eine Klasse diese Schnittstelle implementiert, der generische Typ die gleiche implementierende Klasse ist.

Zum Beispiel:

public class Bar implements Foo<Bar>  {
    Bar someMethod() {
        return new Bar();
    }
}

26voto

Chris Jester-Young Punkte 212385

Ja, das ist möglich (sozusagen; siehe unten). (In der C++-Welt nennt man dies die " Seltsam wiederkehrende Schablonenmuster ", aber das gilt auch für Java):

public interface Recur<T extends Recur<T>> {
    // ...
}

(Beachten Sie die zweite Erwähnung von T . Das ist ein wesentlicher Bestandteil des CRTP).

Außerdem ist dies der Weg java.util.Enum definiert ist, so dass ein Enum-Typ namens Foo muss sich ergeben aus Enum<Foo> Es handelt sich also auch in Java nicht um ein ungewöhnliches Muster.


Ich würde gerne sagen, dass das oben Gesagte das Ende der Geschichte ist, aber tangens weist in seiner Überarbeitung zu Recht darauf hin, dass es nicht ganz robust ist und sich eigentlich nicht so sehr von seiner Antwort unterscheidet.

Es gibt einen Unterschied (soweit ich weiß) zwischen der Recur<T> Lösung, die ich habe, und die Recur<?> Lösung, die Tangens hat:

public interface Recur<T extends Recur<T>> {
    T foo();
}

class A implements Recur<B> {
    @Override
    public B foo() {
        return new B();
    }
}

class B implements Recur<A> {
    @Override
    public A foo() {
        return new A();
    }
}

Mit <T> würde das obige Beispiel nicht kompilieren; mit <?> würde es. Aber das ist nur Haarspalterei; es ändert nichts an tangens' zentralem Punkt, der darin besteht, dass angesichts einer bereits gültigen Recur Implementierung können Sie dafür sorgen, dass nachfolgende Implementierungen den bereits gültigen Typ und nicht sich selbst verwenden. Ich sage immer noch, dass das etwas wert ist, aber es ist nicht mehr wert als die Antwort von tangens.

Abschließend möchte ich Sie bitten, auch die Antwort von tangens hochzustufen, wenn Sie können. (tangens, du solltest deinen Beitrag anfassen, damit ich dich auch hochstufen kann.) Sie haben ein sehr gutes Argument, und es tut mir leid, dass ich es beim ersten Mal übersehen habe. Danke, tangens!

15voto

tangens Punkte 37853

Nein, Sie können sich nicht auf die implementierende Klasse beziehen. Das Beste, was Sie tun können, ist:

public interface Foo<T extends Foo<?> > {
    T someMethod();
}

Auf diese Weise können Sie sicher sein, dass someMethod() gibt ein Objekt zurück, das die Funktion Foo .


EDIT :

Selbst bei einer Schnittstellendefinition wie dieser:

public interface Foo<T extends Foo<T > > {
    T someMethod();
}

Sie können eine Klasse definieren Bar2

public class Bar2 implements Foo<Bar2 > {
    @Override
    public Bar2 someMethod() {
        return new Bar2();
    }
}

Und dann können Sie eine Klasse definieren Bar die Folgendes implementiert Foo kehrt aber nicht zurück Bar pero Bar2 :

public class Bar implements Foo<Bar2 > {
    @Override
    public Bar2 someMethod() {
        return new Bar2();
    }
}

Die ursprüngliche Frage war, ob man sich gegen die Verwendung der Schnittstelle wie Bar hat.

Und die Antwort lautet: Nein.


EDIT :

Angelika Langer gibt eine schöne Erklärung zu Wie kann ich "Enum<E extends Enum<E>>" entschlüsseln?

0voto

fastcodejava Punkte 37539

Dies ist aus folgenden Gründen nicht möglich Typ Löschung .

EDIT :

Ich wurde heruntergestimmt, hier ist eine weitere Erklärung:

public interface Foo<T>;

T von oben ist zur Laufzeit verfügbar, kann also nicht überprüft werden. Allerdings könnte man benutzerdefinierte Annotation, die dies erzwingen könnte.

-4voto

Yoni Roit Punkte 27312

Ich kann auf dieser Website kein einfaches "Nein" einreichen (der Körper ist zu kurz), also geht es hier weiter.

Non.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X