Generics



Generics










Zu den Neuerungen in Java 5 in Besitz sein von
die im JSR 14
beschriebenen Generics.
Mit Generics (“Generizität”, “generische Elemente”) werden im Java-Umfeld Sprachmittel bezeichnet,
mit denen Klassen und Methoden mit Typparametern parametrisiert werden können,
um Typsicherheit trotz generischer Programmierung zu zuteil werden lassen.

Generics werden nur während jener Kompilierung ausgewertet.
Jener entstehende Bytecode ist abwärtskompatibel.

Jener folgende Text beschreibt nur Grundlagen zu Generics.
Weitergehende Informationen finden Sie zum Musterbeispiel unter:






Inhalt



  1. Einfaches Generics-Anwendungsbeispiel
  2. Mischung aus Sourcecode mit und ohne Generics
  3. Generische Stil selbst erstellen
  4. Generische Methode selbst erstellen
  5. Typeinschränkung

    Kovarianz für Arrays, Invarianz für Generics, “extends”
  6. Wildcards

    Wildcard-Arten,

    “<? extends>” versus “<T extends>”,

    “List” versus “List<?>”,

    “List<?>” versus “List<Object>”,

    “List<? extends Number>” versus “List<Number>”,

    “<? super T>” versus “<? extends T>”,

    Musterbeispiel mit “<? super T>” und “<? extends T>”
  7. Generics mit Enums
  8. Zu welcher Zeit werden Raw-Typen gewünscht?
  9. Diamond Operator (ab Java 7)







Einfaches Generics-Anwendungsbeispiel



Die Syntax von Generics besteht in den einfachen Fällen aus einem Typnamen, jener in spitze Winkelklammern mitgemeint wird
und meistens hinter einem zu spezifizierendem Klassennamen steht.
Z. B. für jedes eine Verkettete Liste aus Strings:


Ohne Generics:  List meineListe = new ArrayList();

meineListe.add( "Hallo" );

Zeichenkette s = (Zeichenkette) meineListe.get( 0 );
Mit Generics: List<Zeichenkette> meineListe = new ArrayList<Zeichenkette>();

meineListe.add( "Hallo" );

Zeichenkette s = meineListe.get( 0 );

Die Variante mit Generics gewünscht beim Vorlesung halten keinen Typecast.
Noch wichtiger: Wenn statt dem Zeichenkette zum Musterbeispiel ein Unbestechlich-Objekt hinzugefügt würde,
würde ohne Generics erst zur Spielzeit eine Exception geworfen,
während mit Generics jener Compiler diesen Fehler schon während jener Kompilierung feststellt:


Ohne Generics:  List meineListe = new ArrayList();

meineListe.add( new Unbestechlich(42) );

Zeichenkette s = (Zeichenkette) meineListe.get( 0 ); // <-- Spielzeit-Exception !
Mit Generics: List<Zeichenkette> meineListe = new ArrayList<Zeichenkette>();

meineListe.add( new Unbestechlich(42) ); // <-- Kompilierfehler

Zeichenkette s = meineListe.get( 0 );

Dies hier gezeigte Hinzufügen von Typinformationen per Generics kann nur uff Interfaces, Klassen und Methoden angewendet werden,
die zu diesem Zweck vorbereitet sind, wie zum Musterbeispiel
List,
ArrayList,
weitere Collections und eigene Klassen.





Mischung aus Sourcecode mit und ohne Generics



Eine Mischung aus Sourcecode mit und ohne Generics sollte nachher Möglichkeit vermieden werden, da dies verwirrend sein kann und zu Fehlern resultieren kann.
Im Gegensatz dazu Java lässt es zu, wie folgendes lauffähiges Musterbeispiel zeigt:


import java.util.*;

public class GenericsTest1
{
   public static void main( Zeichenkette[] args )
   {
      List<Zeichenkette> listeMitGenerics = new ArrayList<Zeichenkette>();
      listeMitGenerics.add( "Hallo1" );
      methodeOhneGenerics( listeMitGenerics );

      List listeOhneGenerics = new ArrayList();
      listeOhneGenerics.add( "Hallo2" );
      methodeMitGenerics( listeOhneGenerics );
   }

   static void methodeOhneGenerics( List lst )
   {
      System.out.println( lst.get( 0 ) );
   }

   static void methodeMitGenerics( List<Zeichenkette> lst )
   {
      System.out.println( lst.get( 0 ) );
   }
}

Jener methodeOhneGenerics wird die listeMitGenerics überreichen und umgekehrt wird
jener methodeMitGenerics die listeOhneGenerics überreichen.

Folgendes Musterbeispiel zeigt, zu welchen Problemen eine Mischung resultieren kann:


import java.util.*;

public class GenericsTest2
{
   public static void main( Zeichenkette[] args )
   {
      List<Zeichenkette> listeMitGenerics = new ArrayList<Zeichenkette>();
      List listeOhneGenerics = listeMitGenerics;

      System.out.println( listeMitGenerics.getClass() == listeOhneGenerics.getClass() ); // true

      listeOhneGenerics.add( new Unbestechlich(42) ); // kein Kompilierfehler (obwohl fast wie Zeichenkette-Verkettete Liste)

      Zeichenkette s = listeMitGenerics.get( 0 );     // <-- ClassCastException zur Spielzeit!
   }
}

Während jener listeMitGenerics kein Unbestechlich-Objekt hinzugefügt werden könnte,
ist dies jedoch mit jener mit dem “Raw Type” List deklarierten listeOhneGenerics möglich, obwohl die Verweis dieselbe ist.
Obwohl es keinen Typecast gibt, wird zur Spielzeit eine ClassCastException geworfen.

Jener Grund für jedes dieses Verhalten ist, dass die Generics-Informationen nur zur Kompilierzeit vohanden sind,
wohl nicht mehr zur Spielzeit, da sie im Bytecode jener .class-File fehlen (wie jener Vergleich jener beiden Klassen im Musterbeispiel zeigt).





Generische Stil selbst erstellen



Folgendes Musterbeispiel zeigt die Definition und Software jener einfachen generischen Stil MeineGenerischeKlasse:


public class GenericsTest3
{
   public static void main( Zeichenkette[] args )
   {
      MeineGenerischeKlasse<Double> mgk = new MeineGenerischeKlasse<Double>();
      mgk.setAttribut( new Double( 3.14 ) );
      Double d = mgk.getAttribut(); // ohne Typecast
      System.out.println( d + " (" + mgk.getAttribut().getClass() + ")" );
   }
}

class MeineGenerischeKlasse<T>
{
   private T attribut;

   void setAttribut( T attribut ) { this.attribut = attribut; }

   T getAttribut() { return attribut; }
}

Die generische Stil MeineGenerischeKlasse wird mit dem gewünschten Typ übrig <T> parametrisiert.
Unter diesem Namen kann jener “parametrisierte Typ” denn “Typ-Variable” in den Attributen und Methoden jener Stil verwendet werden.
Statt “T” könnte ein beliebiger Name (außer den reservierten) verwendet werden.
Weit verbreitet sind einzelne große Buchstaben,
zum Musterbeispiel T für jedes Typ, E für jedes Element und Kalium/Vanadium für jedes Key/Value.

Beiläufig Interfaces können mit Generics definiert werden:


interface MeinStackInterfaceMitGenerics<T>
{
   public void push( T obj );
   public T pop();
}

Statt nur einem einzelnen Typ können sekundär mehrere Typen überreichen werden:


class MeineGenerischeKlasse3<T1,T2,T3>
{
   void meineMethode( T1 parm1, T2 parm2, T3 parm3 ) { /* ... */ }
}





Generische Methode selbst erstellen



Nicht nur Klassen, sekundär Methoden können generisch sein:


import java.util.*;

public class GenericsTest4
{
   public static void main( Zeichenkette[] args )
   {
      List<Double> dd = new ArrayList<Double>();
      dd.add( 1.2 ); // Autoboxing
      dd.add( 2.3 );
      dd.add( 3.4 );
      dd.add( 4.5 );
      System.out.println( findeIndex( dd, 3.4 ) );
   }

   static <T> int findeIndex( List<T> meineListe, T meinObjekt )
   {
      for( int i = 0; i < meineListe.size(); i++ ) {
         if( meineListe.get( i ).equals( meinObjekt ) ) return i;
      }
      return -1;
   }
}

Beim Funktionsaufruf jener generischen Methode findeIndex() wird jener Typ nicht explizit überreichen, sondern unabsichtlich erkannt.

Beiläufig hierbei können mehrere Typen vorgegeben werden:


   <T1,T2> T2 meineMethode( T1 parm1, T2 parm2 )
   {
      // ...
   }





Typeinschränkung




Kovarianz für Arrays


Weil Arrays kovariant sind und Unbestechlich von Number methodisch ist, ist Unbestechlich[] eine Herleitung von Number[].
Dies kann zu Laufzeitfehlern resultieren:


   Number[] a = new Unbestechlich[1];
   a[0] = new Double( 3.14 );  // <-- kein Kompilierfehler, wohl Laufzeitfehler

Arrays sind “reified”: Sie Kontakt haben und kontrollieren die Elementtypen zur Spielzeit.



Invarianz für Generics


Obwohl Unbestechlich von Number methodisch ist, ist ArrayList<Unbestechlich> keine Herleitung von ArrayList<Number>
und folgender Label führt zu einem Kompilierfehler:


   ArrayList<Number> a = new ArrayList<Unbestechlich>();  // <-- Kompilierfehler

Dies wird denn “Invarianz” bezeichnet: Die Ableitungsbeziehung zwischen Typargumenten überträgt sich nicht uff generische Klassen,
es gibt keine Kovarianz für Generics.
Damit ist (unterschiedlich denn für Arrays) Typsicherheit gewährleistet.
Generics sind “non-reified”, da sie per “Type Erasure” implementiert sind:
Die Typen werden zur Kompilierzeit überprüft und anschließend wird die Typinformation weit.

Die Zuweisung einer Unbestechlich-Verkettete Liste zu einer Number-Verkettete Liste ist trotzdem möglich, sie muss nur unterschiedlich formuliert werden:
Entweder per “bounded type parameter” wie im Folgenden gezeigt wird
oder per “upper bounded wildcard”, wie unten gezeigt wird.



“extends”


Mit dem Schlüsselwort “extends” kann jener erlaubte Typ eingeschränkt werden uff Ableitungen einer bestimmten Stil
(“bounded type parameter”):


import java.math.BigDecimal;

public class GenericsTest5
{
   public static void main( Zeichenkette[] args )
   {
      Unbestechlich      ii = onlyPositiv( new Unbestechlich( 42 ) );
      BigDecimal   bd = onlyPositiv( new BigDecimal( 4711 ) );

      Zeichenkette       s  = "Bla";
      StringBuffer sb = new StringBuffer( "Blubb" );

      System.out.println( laengererText( s, sb ) );
   }

   static <T extends Number> T onlyPositiv( T parm )
   {
      return ( parm.doubleValue() >= 0 ) ? parm : null;
   }

   static <T extends CharSequence> T laengererText( T parm1, T parm2 )
   {
      return ( parm1.length() > parm2.length() ) ? parm1 : parm2;
   }
}


Beiläufig hierbei können wieder mehrere Typen vorgegeben werden:


   <T1 extends Number, T2 extends CharSequence> T2 meineMethode( T1 parm1, T2 parm2 )
   {
      // ...
   }


Zusätzlich “&” kann die Implementierung zusätzlicher Interfaces gefordert werden, wodurch [Type1] eine Stil sein kann,
wohl allesamt weiteren Typen ([IType2], [IType3], …) Interfaces sein zu tun sein:


   <T extends [Type1] & [IType2] & [IType3]> T meineMethode( T parm )
   {
      // ...
   }



Beiläufig rekursive Verwendung ist möglich (“recursive type bound”):


   <T extends [Type1]<T>> T meineMethode( T parm )
   {
      // ...
   }


   // Vorlaeufiges konkretes Musterbeispiel zur Maximum-Suche in einer Verkettete Liste mit "mutually comparable" Elementen
   // (weiter unten finden Sie eine verbesserte Version):
   <T extends Comparable<T>> T max( List<T> list )
   {
      T result = list.get( 0 );
      for( T t : list )
         if( t.compareTo( result ) > 0 ) result = t;
      return result;
   }





Wildcards




Wildcard-Arten


Es gibt drei Arten von Wildcards und zusätzlich die Möglichkeit jener Verknüpfung mehrerer Typen:


<?> Beliebiger Typ (vermeidet Compiler-Warnung) (“unbounded wildcard”)
<? super [Type]> Superklasse von [Type] (“lower bounded wildcard”)
<? extends [Type]> Von [Type] (Stil oder Interface) abgeleiteter Typ (“upper bounded wildcard”)
<? extends [Type1] & [IType2] & [IType3]> Subtyp von mehreren Typen (außer dem ersten Typ nur Interfaces erlaubt) (“multiple bounds”)



“<? extends [Type]>” versus “<T extends [Type]>”


Zum Musterbeispiel


List<? extends Comparable> meineMethode( List<? extends Comparable> list ) { /* ... */ }

ist in vielen Fällen vergleichbar mit


<T extends Comparable> List<T> meineMethode( List<T> list ) { /* ... */ }

Wenn jener Typ <T> weiter zum Musterbeispiel intrinsisch jener Stil oder Methode gewünscht wird,
oder wenn sichergestellt werden muss, dass beim Unbekannte und für jener Rückgabe identische Typen verwendet werden,
muss die zweite Form gewählt werden.
Ferner kann die erste Variante verwendet werden.



“List” versus “List<?>”


Beiläufig wenn Sie den Typ nicht Kontakt haben oder verschiedenartige Objekttypen verwenden wollen,
sollten Sie nicht Raw-Typen verwenden, wie zum Musterbeispiel Class oder List,
sondern immer generische Typen, wie zum Musterbeispiel Class<?>, List<?> oder List<Object>.

C/o Raw-Typen kann es leichtgewichtig zu den oben
beschriebenen Fehlern und zur ClassCastException kommen.
C/o generischen Typen (wie z.B. List<?> und List<Object>) verhindert jener Compiler (wenn Sie keine Warnungen unterdrücken)
eine ClassCastException und die Verwendung nicht erlaubter Methoden.

Außerdem kann für Verwendung von Raw-Typen Information verloren umziehen.
Folgende Zeilen (mit generischem Class<?>) laufen fehlerfrei,
weil die Klasseninformation denn “Runtime Type Token” sowohl Kompilier- denn sekundär Laufzeitinformationen enthält
(ersetzen Sie meinpackage.MeineKlasse z.B. durch java.weit.Zeichenkette und MeineAnnotation durch Deprecated):


Class<?> c = Class.forName( "meinpackage.MeineKlasse" );
MeineAnnotation a = c.getAnnotation( MeineAnnotation.class );

Welche Zeilen (ohne <?>) sind dagegen nicht kompilierbar:


Class c = Class.forName( "meinpackage.MeineKlasse" );
MeineAnnotation a = c.getAnnotation( MeineAnnotation.class );

Dies folgende Musterbeispiel zeigt, wie Class<?> für jedes zusammenführen typsicheren heterogenen Container genutzt werden kann,
jener Instanzen verschiedener Typen typsicher speichern kann:


class TypsichererHeterogenerContainer
{
   private Map<Class<?>,Object> map = new HashMap<Class<?>,Object>();

   public <T> void putObject( Class<T> clss, T obj ) { map.put( clss, clss.cast( obj ) ); }

   public <T> T getObject( Class<T> clss ) { return clss.cast( map.get( clss ) ); }
}

Interessant ist hierbei jener “dynamische Typecast” mit “clss.cast()” in getObject().
In putObject() ist ebenfalls ein solcher Typecast: Er dient wohl lediglich zur Vermeidung von Fehlern durch Raw-Typen.



“List<?>” versus “List<Object>”


Zwischen den generischen Typen List<?> und List<Object> gibt es wichtige Unterschiede.
Während folgende Zuweisung erlaubt ist:


List<?>      wildcardListe = new ArrayList<Unbestechlich>();

führt folgende Zuweisung zu einem Kompilierfehler (wegen jener Invarianz von Generics):


List<Object> objectListe   = new ArrayList<Unbestechlich>();  // <-- Kompilierfehler

Beiläufig für jener Verwendung jener Methoden kann es Einschränkungen schenken.
Während folgende Zeilen erlaubt sind:


List<Object> objectListe   = new ArrayList<Object>();
objectListe.add( new Unbestechlich(42) );

resultieren folgende Zeilen zu einem Kompilierfehler:


List<?>      wildcardListe = new ArrayList<Unbestechlich>();
wildcardListe.add( new Unbestechlich(42) );  // <-- Kompilierfehler

Einer List<Object> kann aus diesem Grund keine List<Unbestechlich> zugewiesen werden,
wohl es können Unbestechlich-Objekte übrig add() hinzugefügt werden.

C/o einer List<?> ist es umgekehrt:
Ihr kann eine List<Unbestechlich> zugewiesen werden,
wohl es können keine Unbestechlich-Objekte übrig add() hinzugefügt werden.

Dies mag initial widersprüchlich erscheinen. Jener Grund ist folgender:

  • List<?> steht für jedes eine homogene Verkettete Liste von Elementen desselben Typs (oder Ableitungen derselben Superklasse), wodurch jener Typ unbekannt ist.
    Da jener Typ unbekannt ist, darf nicht reibungslos ein Objekt eines vielleicht anderen Typs übrig add() hinzugefügt werden,
    um keine ClassCastException zu riskieren.
  • List<Object> steht für jedes eine heterogene gemischte Verkettete Liste von Elementen mit unter Umständen verschiedenen Typen.
    Da verschiedene Typen erlaubt sind, ist sekundär dies Hinzufügen eines Integers per add() zugelassen.



“List<? extends Number>” versus “List<Number>”


Die Unterschiede zwischen den generischen Typen List<? extends Number> und List<Number> sind in etwa dieselben
wie die oben genannten zwischen List<?> und List<Object>.
Während folgende Zuweisung einer Unbestechlich-Verkettete Liste erlaubt ist:


List<? extends Number> extNumberListe = new ArrayList<Unbestechlich>();

führt folgende Zuweisung zu einem Kompilierfehler (wegen jener Invarianz von Generics):


List<Number>           numberListe    = new ArrayList<Unbestechlich>();  // <-- Kompilierfehler

Beiläufig für jener Verwendung jener Methoden gibt es wieder Einschränkungen.
Während folgende Zeilen erlaubt sind:


List<Number>           numberListe    = new ArrayList<Number>();
numberListe.add( new Unbestechlich(42) );

resultieren folgende Zeilen zu einem Kompilierfehler:


List<? extends Number> extNumberListe = new ArrayList<Unbestechlich>();
extNumberListe.add( new Unbestechlich(42) );  // <-- Kompilierfehler

Einer List<Number> kann aus diesem Grund keine List<Unbestechlich> zugewiesen werden,
wohl es können Unbestechlich-Objekte übrig add() hinzugefügt werden.

C/o einer List<? extends Number> ist es umgekehrt:
Ihr kann eine List<Unbestechlich> zugewiesen werden,
wohl es können keine Unbestechlich-Objekte übrig add() hinzugefügt werden.

Beiläufig wenn es initial seltsam erscheint, dass einer <? extends Number>-Verkettete Liste kein Unbestechlich hinzugefügt werden kann,
so ist jener Grund doch reibungslos: Da jener <? extends Number>-Typ unbekannt ist,
könnte es ja sekundär eine Double-Verkettete Liste sein, und dann könnte ein hinzugefügter Unbestechlich zu einer ClassCastException resultieren.



“<? super T>” versus “<? extends T>”


Zu welcher Zeit muss “<? super T>” und zu welcher Zeit “<? extends T>” verwendet werden?

Die grundsätzliche Regel für jedes Input-Unbekannte lautet:

C/o “Konsumenten” wird “<? super T>” und für “Produzenten” “<? extends T>” verwendet.

Comparable” ist immer ein Konsument, weil er T-Instanzen verwendet (“verbraucht”).
Deswegen sollte immer “Comparable<? super T>” verwendet werden.
Analoges würde für jedes “Comparator” gelten.
Für den Fall ein Collection-Inputparameter denn Input für jedes ein Ergebnis fungiert (aus diesem Grund Instanzen konsumiert),
kann sekundär hierbei “Collection<? super E>” sinnvoll sein
(wie in folgender Stack-Popmusik-Methode: “void popAll( Collection<? super E> destination )“).
Im Allgemeinen wird “super” in eigenen Deklarationen lieber selten verwendet.

C/o Input-Parametern, die sowohl denn Konsument denn sekundär denn Produzent verwendet werden, zeugen Wildcards keinen Sinn.

Beiläufig für Return-Typen sollten Wildcards möglichst vermieden werden.

Im folgenden Musterbeispiel dient jener Methodenparameter “List<? extends T>” denn Produzent, da er T-Instanzen zur Verfügung stellt.
Deswegen wird “extends” verwendet.



Musterbeispiel mit “<? super T>” und “<? extends T>”


Nicht allesamt dies Interface Comparable implementierende Klassen implementieren Comparable<EigeneKlasse>,
wenige implementieren Comparable<SuperKlasse>.
Die im folgenden Musterbeispiel gezeigte Stil AtomicLongComparable ist hierfür ein Musterbeispiel:
Sie implementiert Comparable<AtomicLong>, welches sinnvoll ist,
damit außer mit AtomicLongComparable-Objekten sekundär mit AtomicLong-Objekten verglichen werden kann.

Zum Besten von solche Klassen funktioniert die oben
gezeigte Spezifikation einer generischen max()-Methode nicht,
sondern es muss eine verbesserte Variante verwendet werden.
Dies folgende Musterbeispiel zeigt sowohl die ursprüngliche (hier nicht einsetzbare) findeMaximumOhneWildcards()-Methode
denn sekundär die neue findeMaximumMitWildcards()-Methode mit verbesserter generischer Spezifikation.
(Die Programmierung jener findeMaximum...()-Methoden erfolgt nur zur Erläuterung jener Deklarationsoptionen,
in jener Realität sollte natürlich stattdessen Collections.max() verwendet werden.)

Damit dies Musterbeispiel kompilier- und lauffähig ist, muss die Zeile mit dem Kompilierfehler auskommentiert werden.
Jener Komplilierfehler lautet:
Bound mismatch: The generic method [...] is not applicable for the arguments [...]. The inferred type [...] is not a valid substitute for the bounded parameter [...]“.


import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

public class GenericsTest6
{
   public static void main( Zeichenkette[] args )
   {
      List<AtomicLongComparable> lngLst = new ArrayList<AtomicLongComparable>();
      lngLst.add( new AtomicLongComparable() );
      lngLst.add( new AtomicLongComparable( 99 ) );
      lngLst.add( new AtomicLongComparable( 42 ) );

      System.out.println( findeMaximumMitWildcards(  lngLst ) ); // funktioniert
      System.out.println( findeMaximumOhneWildcards( lngLst ) ); // <-- Kompilierfehler
   }

   // Verbesserte Version mit Wildcards:
   static <T extends Comparable<? super T>> T findeMaximumMitWildcards( List<? extends T> list )
   {
      T result = list.get( 0 );
      for( T t : list )
         if( t.compareTo( result ) > 0 ) result = t;
      return result;
   }

   // Urspruengliche Version ohne Wildcards:
   static <T extends Comparable<T>> T findeMaximumOhneWildcards( List<T> list )
   {
      T result = list.get( 0 );
      for( T t : list )
         if( t.compareTo( result ) > 0 ) result = t;
      return result;
   }
}

class AtomicLongComparable extends AtomicLong implements Comparable<AtomicLong>
{
   private static final long serialVersionUID = 0L;

   public AtomicLongComparable() { super(); }
   public AtomicLongComparable( long lng ) { super( lng ); }

   @Override public int compareTo( AtomicLong o )
    get() > o.get() ) ? 1 : ( get() < o.get() ) ? -1 : 0;
   
}





Generics mit Enums



Die Verwendung von Generics mit Enum-Klassen ist homolog wie für anderen Klassen.
In folgendem Musterbeispiel implementiert dies Enum MeinEnum dies Interface Calculator.
Die beiden Methoden testAllCalculators1() und testAllCalculators2()
vorexerzieren zwei verschiedene Möglichkeiten für jedes Methodendeklarationen,
um für jedes allesamt Enum-Elemente die calculate()-Berechnungsmethode für jedes den Beispielparameter 42 aufzurufen.

Informationen zu Enums finden Sie unter java-enums.htm.


import java.util.*;

public class GenericsTest7
{
   public static void main( Zeichenkette[] args )
   {
      int i = 42;
      testAllCalculators1( MeinEnum.class, i );
      testAllCalculators2( Arrays.asList( MeinEnum.values() ), i );
   }

   // Variante 1:
   static <T extends Enum<T> & Calculator> void testAllCalculators1( Class<T> calcs, int i )
   {
      for( Calculator c : calcs.getEnumConstants() )
         System.out.println( c + ": " + i + " -> " + c.calculate( i ) );
   }

   // Variante 2:
   static void testAllCalculators2( Collection<? extends Calculator> calcs, int i )
   {
      for( Calculator c : calcs )
         System.out.println( c + ": " + i + " -> " + c.calculate( i ) );
   }
}

interface Calculator
{
   int calculate( int i );
}

enum MeinEnum implements Calculator
{
   ITEM1 { public int calculate( int i ) { /* ... */ return 2 * i; } },
   ITEM2 { public int calculate( int i ) { /* ... */ return 7 * i; } };
}





Zu welcher Zeit werden Raw-Typen gewünscht?



Normalerweise sollten Raw-Typen nicht mehr verwendet werden.
Im Gegensatz dazu es gibt zwei Ausnahmen:

In Klassenbezeichnungen (“Class Literals”) können keine Generics verwendet werden, sondern nur Raw-Typen:

List.class“, “Zeichenkette[].class“, “int.class” und “void.class” sind erlaubt,

wohl “List<Zeichenkette>.class” und “List<?>.class” nicht.

Ähnliches gilt für jedes den instanceof-Operator:

obj instanceof List” ist erlaubt, wohl “obj instanceof List<Zeichenkette>” nicht.

Eine entsprechende Nachfrage könnte wie folgt aussehen:


if( obj instanceof List ) {
   List<?> lst = (List<?>) obj;
   // ...
}

Im Gedächtnis behalten Sie, dass es Methoden gibt, für denen man den Eindruck bekommen kann, dass Generics vergessen wurden.
Z. B. ist Folgendes nicht kompilierbar (“cannot convert from Object[] to Zeichenkette[]“)
obwohl es fast wie triftig aussieht:


List<Zeichenkette> list = Arrays.asList( new Zeichenkette[] { "abc", "xyz" } );
Zeichenkette[] array = list.toArray();

Rechtsbehelf ist für diesem Musterbeispiel leichtgewichtig möglich:


List<Zeichenkette> list = Arrays.asList( new Zeichenkette[] { "abc", "xyz" } );
Zeichenkette[] array = list.toArray( new Zeichenkette[list.size()] );





Diamond Operator (ab Java 7)



Z. B. eine Map von Zeichenkette-Listen wird normalerweise wie folgt definiert:


Map<Zeichenkette,List<Zeichenkette>> strListenMap = new HashMap<Zeichenkette,List<Zeichenkette>>();

Ab Java 7 erlaubt jener Compiler sekundär eine verkürzte Schreibweise.
Sind allesamt Typinformationen prestigevoll, so können beim new-Operator die Typparameter entfallen und es genügen die spitzen Klammern
(denn “Diamond Operator”):


Map<Zeichenkette,List<Zeichenkette>> strListenMap = new HashMap<>();










Weitere Themen: andere TechDocs | Annotations


© 2008-2010 Torsten Hupe, Aachen



Sie sehen Mitgliedsbeitrag: Generics

Website :https://idacorr.net
Categoría: bedeutung

Leave a Reply