2009-08-10 13 views
5

Ich habe ein Problem zu verstehen, Java Generics und ich habe, istJava Generics Kreis

class A<T extends B> { 

    public void fun(T t) { 

    } 
} 

class B { 
    A a; 

    public void event() { 
     a.fun(this); 
    } 

} 

Das Problem an diesem Beispiel vereinfacht, dass dies eine Warnung erzeugt, weil ein innen B definiert ist, aber A ist es bereits mit als generischer Typ.

Mein erster Instinkt wäre, dass mein Design falsch ist, aber in diesem Fall kann ich es nicht ändern. A ist wie eine Sammlung und B ist wie ein Knoten in der Sammlung, den Benutzer überschreiben sollen. Bestimmte Ereignisse in B passieren können, die aus der Mutter A.

Aber da A angegeben werden müssen definiert sind allgemein mit B, wie vermeide ich die Kompilierung Warnung innerhalb B.event()

Dank

+0

Die einzige Warnung, die ich sehen kann, ist die Verwendung von A als Rohtyp. Wenn das nicht die Warnung ist, auf die Sie sich beziehen, seien Sie bitte genauer und sagen Sie uns, welchen Compiler Sie verwenden. – skaffman

Antwort

11

-Code

public class A<T extends B> { 
    public void fun(T t) { 
    } 
} 

public class B { 
    A<B> a; 

    public void event() { 
     a.fun(this); 
    } 
} 

Die Warnung besiegt.

Grund

Variablen vom Typ A sollte mit einem spezifischen Klassentyp deklariert werden, wie sie in der generic Klasse Unterschrift vorgeschlagen (A<T extends B>).

Auflösung

Während dies die Warnung Compiler löst, bleibt das zugrunde liegende Problem. Laurence bietet eine hervorragende Erklärung und Lösung für das Kernproblem.

13

das Problem ist, dass man eine rohe Art auf dieser Linie verwenden:

A a; 

Sie benötigen einen Typen für A den Typparameter (T) angeben.

Man könnte so etwas tun:

A<B> a; 

aber an allen generischen A könnte auch nicht sein, dann, wenn ich Ihre Aussage des Problems zu verstehen. Sie wollen wahrscheinlich so etwas wie dies zu tun:

class A<T> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
}  

oder auch diese:

class A<T extends B<? extends T>> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<? super B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
} 

Es gibt ein paar Variationen in-zwischen diesen sind, die auch möglicherweise nützlich sind. Das letztere Beispiel ist das allgemeinste (aber offensichtlich auch das komplizierteste).

Die class A<T extends B<? extends T>> stellt sicher, dass der Typparameter zu A ein B. ist. Da B selbst generisch ist und diesen zyklischen Typparameter hat, müssen Sie am Ende sagen B<? extends T> (einfach sagen, dass T hier nicht funktioniert).

Die class B<T extends B<T>> ist so nahe wie möglich, um einen "Selbsttyp" in Java zu emulieren. So kann B über seinen (fast) konkreten Subtyp sprechen. Wenn man B unterklassifiziert, sagt man etwas wie "class C extends <B<C>>". Dies ist nützlich, da jetzt der Typ C.a eigentlich A<? super B<C>> ist.

Das Bit ? super im letzten Beispiel ist nur nützlich, wenn Sie ein B mit einem A verbinden möchten, das nicht für genau den gleichen Typ von B ist. Konkret angenommen, Sie hätten eine A<Shape> und eine Circle (die Shape erweitert, die B erweitert). Mit dem Super-Wildcard können Sie sie zusammen verwenden. Ohne sie würden Sie eine A<Circle> anstelle einer A<Shape> für Ihre Circle benötigen.

+0

Das ist richtig und ein großartiges Beispiel für Platzhalter. –