2012-10-06 12 views
6

Ich überprüfte den Code von jemand anderem neulich und ich stieß auf eine Zeile, die einige Bedenken aufwarf. Um zu vereinfachen, sagen wir, ich habe eine generische Klasse A und eine abstrakte Klasse B. Ist die folgende Instanziierung erlaubt und wenn ja, warum?Generics Wildcard-Instanziierung

Object obj = new A<? extends B>(); 

Ich habe persönlich nie eine Instanziierung wie die oben genannten, obwohl eine Erklärung wie

A<? extends B> obj = null; 

würde sicher halten gesehen. Ich habe immer den Platzhalter in Generics verwendet, um Methodenparameter zu deklarieren, so dass ich einfach nicht die Erfahrung habe.

+0

Welche Version von Java verwenden Sie? –

+0

bezogen, wenn nicht dupliziert: http://StackOverflow.com/Questions/9147129/creating-new-generic-Object-with-Wildcard und http://StackOverflow.com/Questions/12200136/Cannot-Instantiate-Type-in- Generika? lq = 1 –

Antwort

3

Eigentlich new A<? extends B>() kompiliert nicht. Es ist konsequent seit Java 5 ungültig gewesen.

Aber ich denke, Ihr ursprüngliches Beispiel war etwas wie new A<X<? extends B>>(). Letzteres ist in neueren Versionen von Java zulässig.

Die Idee ist, wenn ein Objekt instanziiert wird, kann der Wert für Typparameter beliebiger Nicht-Wildcard-Typ sein. ? extends B ist ein Platzhalter, daher ist er nicht zulässig. Aber X<? extends B> ist kein Platzhalter, obwohl es einen Platzhalter als eine Komponente hat. Sie können also sagen: new A<X<? extends B>>().

Die Regeln machen Sinn, wenn Sie so darüber nachdenken. Letztendlich ist es ein Nebenprodukt der grundlegenderen Regel, dass ein Wildcard-Typ wie ? extends B nicht der deklarierte Typ eines Feldes oder einer Variablen sein kann. Wenn A als

class A<T> { 
    T value; 
} 

definiert wird dann die hypothetische new A<? extends B>().value wäre ein Feld vom Typ? extends B deklariert werden. Da das illegal ist, ist auch die Instanziierung. Aber new A<X<? extends B>>() hat dieses Problem nicht.

+0

Ziemlich gute Antwort, aber ich denke nicht, dass die Argumentation in der zweiten Hälfte macht viel Sinn. Wenn eine Variable "a" als "A " eingegeben wird, bedeutet das nicht, dass "a.value" * als * deklariert ist. extends B' - "Wert" wird als "T" erklärt, wobei "A" "T" erklärt. 'a.value' bewertet * zu'? erweitert B'. Siehe meine Antwort auf eine ähnliche Frage [hier] (http://stackoverflow.com/a/9147768/697449). –

+0

@PaulBellora Zugegeben, ich war im zweiten Teil nicht sehr klar. Was ich sagen wollte, war, dass es einen Unterschied gibt zwischen dem mutmaßlichen Typ von _expression_ 'a.value' und dem deklarierten Typ von _variable_' a.value'. Beachten Sie, dass eine Variable sowohl ein r-Wert als auch ein l-Wert ist. Wenn Sie also eine Variable/ein Feld mit einem Platzhaltertyp erstellen können, ist '? erweitert T '(oder "Super T") wäre es eine inhärent behinderte Variable. Sie könnten es nicht als r-Wert (bzw. l-Wert) verwenden. Nun, das ist erträglich für eine gewöhnliche Referenz "a", aber niemals für "this". – Saintali