Wann braucht es SomeE extends SomeE statt SomeE extends Some?

8

HINWEIS: Diese Frage ist nicht Enum-bezogen, so dass es nicht doppelt ist. Enum sind gezwungen, nur mit sich selbst zu vergleichen, weil Compiler Generierung von Typ Parameter, nicht, weil Java rekursive Typ Parameter / p>

Ich versuche einen Vorteil zu finden, um eine Klasse zu deklarieren als:

%Vor%

versus Erklärung als:

%Vor%

Ich habe versucht, Methoden bereitzustellen, die E zurückgeben, und Methoden, die Some<E> zurückgeben, verschiedene Querverweise in komplizierter Klassenhierarchie und jedes Mal, wenn ich versucht habe, zusätzliche <E> zu entfernen - keine neuen Fehler / Warnungen kamen hoch .

Können Sie mir eine Methode zeigen, die den Vorteil dieser zusätzlichen <E> beweist? Ich nehme an, dass es wegen JDK-Deklarationen einen gibt: <E extends Comparable<? super E>>

Antworten auf andere Fragen zu SO gibt zum Beispiel:

  

Mit dem zusätzlichen Konstrukt wissen Sie, dass jede Klasse erweitert wird   Enum ist nur mit sich selbst vergleichbar.

Aber ich kann diese Theorie leicht brechen:

%Vor%

Trotz der generischen Rekursion kann ich immer noch Hund mit Katze vergleichen:

%Vor%

Transalting Theorie:

  

Sie wissen, dass jede Klasse, die Animal ausdehnt, nur mit sich selbst vergleichbar ist

das ist falsch - ich habe einen Klassenhund, der Tier mit Katze ausdehnt, nicht selbst.

    
Kinga Odecka 18.08.2014, 14:20
quelle

4 Antworten

3

Es gibt sehr wenige Situationen, in denen eine Grenze wie class Some<E extends Some<E>> notwendig ist. Die meiste Zeit schreiben die Leute das, die Grenze wird nicht wirklich im Code verwendet, und class Some<E> würde genauso gut funktionieren.

Es gibt jedoch bestimmte Situationen, in denen die Grenze in class Some<E extends Some<E>> tatsächlich verwendet wird. Zum Beispiel:

%Vor%

Was Ihre Frage angeht - was ist mit class Some<E extends Some> ? Nun, das erste Problem ist, dass Sie einen unformatierten Typ verwenden. Rohtypen sollten niemals in neuem Code verwendet werden. Aber Sie sind nicht überzeugt.

Der Rohtyp mit der obigen Klasse ( class Some<E extends Some> ) wird mit einer Warnung kompiliert (die Sie auf Ihre eigene Gefahr ignorieren können). Der rohe Typ bedeutet jedoch, dass damit auch unsichere Dinge möglich sind.

Es bedarf einiger Anstrengungen, um ein Beispiel zu finden, um zu zeigen, dass es unsicher ist. Hier ist eins:

%Vor%

Der Code wird mit Warnungen, aber ohne Fehler kompiliert und löst zur Laufzeit ein ClassCastException aus.

    
newacct 19.08.2014 08:34
quelle
2

Betreffend die Aussage

  

jedes Mal, wenn ich versucht habe, zusätzliche zu entfernen - keine neuen Fehler / Warnungen kamen auf.

Dies sollte nicht der Fall sein. Es sollte eine Warnung ausgegeben werden, weil Sie den rohen Typ Some verwenden, und das Ergebnis ist fehlende Typsicherheit, wie im Antwort von newacct .

Das Dog / Cat Beispiel ist ein bisschen künstlich und etwas fehlerhaft. Sie haben vorgeschlagen, eine Klasse zu deklarieren

%Vor%

Aber hier bedeutet der Typparameter im Grunde: "Dieser Parameter ( Cat ) ist der Typ, mit dem Objekte dieser Klasse ( Dog ) mit" verglichen werden können. Sie sagen also ausdrücklich , dass ein Dog mit Cat vergleichbar sein sollte. Selbst mit anspruchsvollen Sprachen und intelligenten Compilern liegt es in der Verantwortung der Programmierer, Code zu schreiben, der Sinn macht.

Tatsächlich gibt es nicht viele Fälle, in denen diese selbstreferentiellen generischen Typen notwendig sind. Eines dieser Beispiele ist in diesem FAQ-Eintrag skizziert: Er deklariert eine Struktur von Knoten (d. H , ein Baum), wobei der type-Parameter verwendet werden kann, um die Definition der Struktur Struktur vom tatsächlichen Typ der Knoten zu entkoppeln:

%Vor%

Aber aus meiner persönlichen Erfahrung kann ich sagen, dass wenn Sie denken, dass Sie einen solchen Typ erstellen müssen, sollten Sie gründlich über die Vor- und Nachteile nachdenken. Letzteres bezieht sich hauptsächlich auf eine verringerte Lesbarkeit. Wenn Sie die Wahl zwischen Methoden wie

haben %Vor%

das sind typsicher, oder Methoden wie

%Vor%

die nicht typsicher sind (wegen roher Typen oder einfach weil die Typen nicht generisch sind), dann würde ich letztere bevorzugen. Code wird von Menschen gelesen.

    
Marco13 19.08.2014 10:04
quelle
1

Der Unterschied ist, dass Some<E extends Some> zwei Dinge bedeutet:

  • E ist ein Rohtyp. Kurz gesagt, bei Rohtypen werden alle generischen Informationen aus der Klasse entfernt, was wiederum zu unerwartetem Verhalten führen kann
  • E kann jede Klasse von Some !
  • sein

Umgekehrt bedeutet die Verwendung von Some<E extends Some<E>> :

  • E wird eingegeben
  • E muss die selbe -Klasse der Klasse sein, in der sie deklariert ist

Der rohe Teil ein Problem, aber die größere Implikation sind die Typgrenzen. Dieser Code demonstriert den Unterschied, wobei die "B" -Klassen die Klassen "A" als generischen Typ verwenden (oder versuchen, sie zu verwenden).

%Vor%

Klasse SomeB kompiliert gut - der Typ von E ist nur an Some gebunden, also any Some Klasse, aber die Klasse SomeTB löst einen Kompilierungsfehler aus:

  

Typ Argument SomeTA ist nicht innerhalb der Grenzen der Typ-Variable E

Der Typ von E muss genau mit der enthaltenen Klasse übereinstimmen.

Dies ist wichtig, wenn Sie erwarten, dass Parameter und Rückgabetypen mit der Klasse identisch sind, was normalerweise bei typisierten Klassen der Fall ist.

Der Typ, der von einem unformatierten Typ begrenzt wird, ist weniger ein Problem, weil es immer noch ein Some ist, aber es kann Fälle geben, in denen es einen Unterschied macht (ich kann mir gerade keinen vorstellen).

    
Bohemian 18.08.2014 23:22
quelle
0

Es sieht aus wie zur Zeit hat Some<E extends Some<E>> keinen Vorteil gegenüber Some<E extends Some>

Laut Artikel in Zusammenarbeit mit Java Champions und dem Ersteller von Java Generics FAQ :

Artikel gibt einige Möglichkeiten / Annahmen:

  • Da Enum eine generische Klasse ist, sollten wir sie immer nur in Verbindung mit einem Typ
  • verwenden
  • Java könnte strenger werden und rohe Typen könnten illegal werden
  

Ich denke, Enum wäre ausreichend gewesen.   Allerdings, wie Philip Wadler mich darauf hingewiesen hat, da Enum ein Generikum ist   Klasse, sollten wir es immer nur in Verbindung mit einem Typ verwenden. Im   Zukünftig könnte Java strenger und rohe Typen werden   illegal. Wir haben daher die Wahl, entweder Enum<E extends Enum<E>> zu schreiben   oder Enum<E extends Enum<?>> , von denen die erste Option mehr ist   genau. Auch wenn der Compiler mir momentan keine a zeigt   Unterschied, könnte ich in Zukunft Warnungen sehen, also folge ich diesem Idiom   meine Klasse auch

    
Kinga Odecka 18.08.2014 15:14
quelle