2017-06-30 1 views
0

1) Warum obj4, obj6, obj7 kompilieren Fehler, und obj5 ist in Ordnung? Wo kann ich über Regeln lesen, die die Verwendung solcher generischer gekoppelter Außen-Innen-Klassen regeln? Ich habe nichts direkt auf den Punkt gebracht.Welche Regeln gelten, um Instanzen der generischen äußeren Klasse und ihrer inneren generischen inneren Klasse zu instanziieren und entsprechende Referenzen zu deklarieren?

Wenn ich kein Typ-Argument für Inner-Klasse in Obj3 liefern, ist es in Ordnung (während Inner-Klasse etwas für sein Fld3-Feld vom Typ S gegeben werden muss), aber wenn ich das gleiche mache und nicht liefern Typ für die äußere Klasse - es kompiliert nicht (obj4) - obwohl das Objekt impliziert werden könnte ...

2) Außerdem, warum obj10 kompiliert gut, aber obj11 fehlschlägt? In obj10 Zeile schreibe ich auch outerInstance.new Inner <>(), was für Inner bedeutet, dass S Objekt ist. Aber das ist nicht Problem für die innere, sondern gleichen "Trick" ist Problem für Outer ...

 //in Class A of package com.sth 
     public class MyGen<T> { 
      T fld1; 

      class GenInner<S> { 
       T fld2; 
       S fld3; 
      } 

       // within main of Class Driver of same package com.sth 
       MyGen.GenInner obj1 = new MyGen<String>().new GenInner<Integer>(); 
       MyGen.GenInner obj2 = new MyGen<String>().new GenInner<>(); 
       MyGen.GenInner obj3 = new MyGen<String>().new GenInner(); 
       //MyGen.GenInner obj4 = new MyGen().new GenInner<String>(); //ERR ! 
       MyGen.GenInner obj5 = new MyGen<>().new GenInner<String>(); 

       //MyGen<String>.GenInner obj6; // ERR 
       //MyGen.GenInner<String> obj7; // ERR 
       MyGen<String>.GenInner<Integer> obj8; 
       MyGen.GenInner obj9;  


    MyGen<String>.GenInner<Integer> obj10 = new MyGen<String>().new GenInner<>(); 

    //Type mismatch: cannot convert from MyGen<Object>.GenInner<Integer> to MyGen<String>.GenInner<Integer> 
    //MyGen<String>.GenInner<Integer> obj11 = new MyGen<>().new GenInner<Integer>(); // ERR! 

Diese Antworten auf meine Frage beziehen, aber geben keine Ahnung:

  1. Answer 1
  2. Answer 2
  3. Answer 3
  4. Answer 4
  5. Answer 5
+0

Java 8 lehnt auch 'obj3' ab:" falsch formatierter Typ, einige Parameter fehlen ". –

+0

seltsam, aber mein Eclipse-Compiler für Java SE8 kompiliert obj3 Zeile fein, und kein Problem in Runtime! P.S .: MyGen.GenInner obj3 = new MyGen () .new GenInner(); – LrnBoy

+0

Ich denke, ich sollte genauer sein: Der Compiler von OpenJDK 8 lehnt den Klasseninstanz-Ausdruck ab, der 'obj3' zugewiesen ist. OpenJDK ist auch die Basis des JDK von Oracle, daher hat das eine große Bedeutung. Ich bin nicht der Meinung, dass es richtig ist, es abzulehnen, trotz der ausgezeichneten Antwort von @ Radiodef, aber ich bin sicher, dass es unklug ist, einen solchen Code zu schreiben. Mit wenigen Ausnahmen sollte neuer Code keine unformatierten Typen verwenden (und auch keine seltenen verwenden). –

Antwort

1

Die Beispiele, die sind meist Beispiele für seltenen Arten nicht kompilieren. (Auch, wie von John in den Kommentaren erwähnt, das obj3 Beispiel sollte entweder nicht kompiliert.)

A raw type ist die Art, die durch die Verwendung eines generischen Typs ohne eine begleitende Typ Argumentliste (wie zB gebildet wird Set, wie im Gegensatz zu zB Set<Float>). Ein seltener Typ ist, wenn Sie eine generische äußere Klasse und eine generische innere Klasse haben, von denen eine roh ist und die andere nicht.

von JLS 4.8 Raw Types Genommen:

Genauer gesagt, eine rohe Art definiert eine der sein:

  • Der Referenztyp, der ohne indem sie den Namen einer generischen Typdeklaration gebildet wird eine begleitende Argumentliste.

  • Ein Array-Typ, dessen Elementtyp ein Rohtyp ist.

  • Ein nicht static Elementtyp eines rohen R Typ, der nicht von einer Superklasse oder Superschnitt von R vererbt wird.

(Beachten Sie, dass der Punkt in fett bedeutet, dass, wenn Sie eine rohe Art MyGen haben, dann wird sie nicht static Mitglied Klasse GenInner auch roh sein muss, so dass es nicht so etwas wie zB ein MyGen.GenInner<String> .)

Eine weitere Folge der oben genannten Regeln ist, dass eine allgemeine innere Klasse eines rohen Art kann sich nur als Ausgangstyp verwendet werden:

class Outer<T>{ 
    class Inner<S> { 
     S s; 
    } 
} 

Es ist nicht möglich Inner als teilweise für den Zugriff auf roh Typ (a „selten“ Typ):

Outer.Inner<Double> x = null; // illegal 
Double d = x.s; 

weil Outer selbst roh ist, also so sind alle seine inneren Klassen einschließlich Inner, und so ist es nicht möglich, pa ss jede Art von Argumenten nach Inner.

Es ist ein Fehler bei der Kompilierung auf Typargumente zu einem nicht static Typ Mitglied eines rohen Typs übergibt, die nicht von ihren Superklassen oder Superschnitt vererbt wird.

Es ist ein Fehler bei der Kompilierung, einen Typmember eines parametrisierten Typs als unformatierten Typ zu verwenden.

Dies bedeutet, dass das Verbot von „selten“ Typen auf den Fall erweitert, wenn der Wartetyp parametriert, aber wir versuchen, die innere Klasse als Ausgangstyp zu verwenden:

Outer<Integer>.Inner x = null; // illegal 

Dies ist das Gegenteil des oben besprochenen Falles. Für diesen halbgebackenen Typ gibt es keine praktische Begründung. Im Legacy-Code werden keine Argumenttypen verwendet. In nicht altem Code sollten wir die generischen Typen korrekt verwenden und alle erforderlichen Typargumente übergeben.

Das Beispiel mit obj11 = new MyGen<>().new GenInner<Integer>() ist kein seltener Typ. Es sieht nur wie ein regelmäßiger Fehler der Typrückschluss mit dem Diamanten aus, weil der Ausdruck new MyGen<>() nichts zugewiesen ist. Wenn keine Zuweisung vorhanden ist, wird normalerweise Object angenommen. (Technisch wäre es sein, was die obere Grenze für die Variable vom Typ ist, der Object in diesem Fall ist.)


Auch wenn nicht direkt auf die Frage auf der Hand bezogen, sind nur die folgenden zwei Formen die sollte eigentlich in neuen Code verwendet werden:

MyGen<String>.GenInner<Integer> ok1 = new MyGen<String>().new GenInner<Integer>(); 
MyGen<String>.GenInner<Integer> ok2 = new MyGen<String>().new GenInner<>(); 

Alle anderen (die kompilieren) verwenden rohe Typen und rohe Typen abgeraten.

Verwandte Themen