"Illegale" Implementierung der generischen Methode: Warum erhalte ich keinen Kompilierungsfehler?

8

Ich habe eine Schnittstelle, die eine Methode mit dieser Signatur enthält:

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

Grundsätzlich MergePropertyhandelt es sich um eine Klasse, die NICHT implementiert wird RestartApplicant, und RestartApplicanteine funktionale Schnittstelle, die eine Methode enthält, die für das Verständnis dieses Problems nicht wirklich wichtig ist.

Hier ist der Haken. Wenn ich eine Klasse erstelle, die diese Schnittstelle implementiert, kann ich mit Java den folgenden Code ohne Kompilierungsfehler ausführen:

public class MyImplementation implements MyInterfacePreviouslyDescribed {

    @Override
    public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }
}

Natürlich respektiere ich die Einschränkungen der Implementierung dort nicht. In Anbetracht dieser Unterschrift, die Liste I mit Rück Arrays.asList(...)nicht NICHT brauchen Elemente zu enthalten , die implementieren RestartApplicant. Denken Sie daran, MergePropertynicht implementiert RestartApplicant. Dies wird also höchstwahrscheinlich irgendwo einen Casting-Fehler verursachen.

Trotzdem bekomme ich eine Warnung:

Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>

Meine Frage ist: Warum bekomme ich nur eine Warnung? Es scheint mir, dass ich meinen Code nicht kompilieren kann. Gibt es dafür einen besonderen Grund?

Danke im Voraus.

BEARBEITEN

Nachdem ich ein wenig mit meinem Code gespielt hatte, stellte ich fest, dass, wenn ich die "Generika-Deklaration" auf die Klassenebene verschieben würde, dies führen würde zu:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>

statt nur

interface MyInterfacePreviouslyDescribed<T>

und natürlich

List<P> loadPropertiesFrom(T p1, T p2);

anstatt

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

dann bekomme ich tatsächlich einen Kompilierungsfehler, wenn ich die gleiche "illegale" Implementierung wie zuvor versuche. Es scheint noch seltsamer ...

Akami
quelle

Antworten:

2

Sie können sogar tun:

    @Override
    public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }

im ersten Fall. Dies liegt daran , die überschriebene Methode ist nicht generisch und Löschung für diese sein wird List. Warum ist das erlaubt? Ich weiß ehrlich gesagt nicht, kann etwas mit Abwärtskompatibilität zu tun haben.

In Ihrem zweiten Beispiel scheint es wirklich so zu sein:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {

und in der Implementierung erzwingen Sie, dass die Typen korrekt sind. Tatsächlich ist das zweite Beispiel das intuitive - da es nicht kompiliert wird; und das wird erwartet. Die erste basiert auf einer Kompatibilitätsregel für nicht generische Methoden, die es ermöglicht, dieselbe Löschung zu überschreiben.

Eugene
quelle
Interessant. Das zweite Beispiel scheint doch intuitiver zu sein. Und ja, das fehlende "T" in letzterem war ein Tippfehler
Akami