Generics in Java

Generic programming in Java is enabled by so-called Generics. The term is synonymous with " parameterized types ". The idea is to introduce additional variables to types. This type variables represent the time of implementation of unknown types. Only with the use of classes, interfaces and methods, these type variables are replaced by concrete types. Thus, type-safe programming be guaranteed.

The concept

As of version 5.0 ( "Tiger", published in 2004 ) is also in the Java programming language with generics a syntactic means for generic programming. Thus, classes and methods (methods independent of their classes ) can be parameterized with types. In order for the language to be opened some similar opportunities that present themselves to comparable for the templates in C .

In principle, there are, however, important differences. While parameterized in C via the interface of the type parameter is parameterized in Java directly on the type of the type parameter itself. The source code for a C template should be for the user (ie, at the onset of the type parameter ) must be available, while a generic Java type may also be published as translated bytecode. For several current type parameter, the compiler produces duplicated target code.

For example the function std :: sort in C is the ability to sort all containers that certain methods offer ( here specifically begin () and end (), each an iterator supply ) and its type parameter to 'operator <' implemented (or was explicitly specify a different comparison function ). A disadvantage of the results from this system, is the ( for the programmer! ) Difficult translation. The compiler has no other option than the type parameter in any case, replace it with the required concrete type and all the code to compile again.

Very light may arise from improper type parameters and other problems complicated and incomprehensible compiler messages, which simply related to the fact that the specific requirements are unknown to the type parameter. Therefore, the work with C templates requires a complete documentation of the requirements for a type parameter. Through template metaprogramming most requirements ( base class, presence of methods copyability, assignability, etc.) can also be queried in specific constructs, resulting in more readable error messages result. Although they are standards compliant, these constructs are not supported by all compilers.

In contrast, the generic classes and methods in Java are known requirements (English constraints ) to its own type parameter. In order to sort a collection (no comparator ), which contained elements of type Comparable must be, so have implemented this interface. The compiler only needs to check if the type parameter is a subtype of Comparable, and may have thus ensure that the code is correct ( that is, the required method compareTo is available). Furthermore, one and the same code for all concrete types is used dozens of times and not duplicated.

Practical examples

A program uses an ArrayList to store a list of JButtons.

So far, the ArrayList was fixated on the type Object:

ArrayList al = new ArrayList ();   al.add ( new JButton ("Button 1 "));   al.add ( new JButton ("Button 2 "));   al.add ( new JButton ("Button 3 "));   al.add ( new JButton ("Button 4 "));   al.add ( new JButton ("Button 5 "));   for (int i = 0; i < al.size (); i ) {       JButton button = ( JButton ) al.get ( i);       button.setBackground ( Color.white );   } Note the necessary explicit type conversion (also called " Cast "), and the type of uncertainty that is associated with it. You could accidentally save an object in the ArrayList that is not an instance of the class JButton. The information about the exact type is lost when inserting into the list, so the compiler can not prevent at run time with the explicit type conversion of JButton a ClassCastException occurs.

With generic types in Java, you can:

ArrayList al = new ArrayList ();   al.add ( new JButton ("Button 1 "));   al.add ( new JButton ("Button 2 "));   al.add ( new JButton ("Button 3 "));   al.add ( new JButton ("Button 4 "));   al.add ( new JButton ("Button 5 "));   for (int i = 0; i < al.size (); i ) {       al.get ( i) setBackground ( Color.white ). ;   } When reading an explicit cast is now more necessary when storing it is only possible to place JButtons in the ArrayList al.

From Java7 the instantiation of generic types has been simplified. The first line in the above example, since Java 7 can be written as:

ArrayList al = new ArrayList <> (); The combination of generic types with enhanced for loops can be above example it shorter as:

ArrayList al = new ArrayList <> ();   al.add ( new JButton ("Button 1 "));   al.add ( new JButton ("Button 2 "));   al.add ( new JButton ("Button 3 "));   al.add ( new JButton ("Button 4 "));   al.add ( new JButton ("Button 5 "));   for ( JButton b: al ) {       b.setBackground ( Color.white );   } An example of a generic class that contains two objects of arbitrary, but each the same type, provides the following sample code:

Public class Double Object Of T {      private T object1;      private T object2;      public Double Object ( T object1, object2 T ) {        this.object1 = object1;        this.object2 = object2;      }      public String toString () {        return this.object1 "," this.object2;      }      public static void main ( String [ ] args ) {        Double Object s = new Double Object <> ( "abc ", " def" );        Double Object i = new Double Object <> ( 123,456 );        System.out.println ("Double Object s =" s );        System.out.println ("Double Object i =" i);      }    } variance cases

In Java, the following variance cases can be distinguished. They each offer a completely unique flexibility when dealing with generic types, and are each absolutely statically type-safe.

Invariance

For invariance of the type parameter is unique. This invariance provides the greatest possible freedom in using the type parameter. For example, for the elements of an ArrayList all actions permitted are also allowed on the direct use of a single integer (including autoboxing ). example:

ArrayList list = new ArrayList ();   ...   Integer x = list.get (index);   list.get (index) methodeVonInteger ().;   list.set (index, 98347 ); / / Autoboxing corresponds, Integer.valueOf ( 98347 )   int y = list.get (index); / / Auto- Unboxing These possibilities are bought with little flexibility in the allocation of objects of the generic class itself. For example, the following is not permitted:

ArrayList list = new ArrayList (); and although Integer is derived from Number. The reason is that the compiler can no longer make here is that no type errors occur. With arrays that allow such an assignment, you have had bad experiences:

Number [ ] array = new Integer; / / OK, Integer [ ] is derived from Number [ ]   array = new Double (5.0 ); / / ArrayStoreException exception at runtime: Double - > Integer                                        / / Are not assignment-compatible covariance

This is known as co-variant arrays, which states:

Or more generally:

It behaves so the array type with respect to the inheritance hierarchy, as well as the type parameter. Covariance is also possible with generic types, but only with restrictions, so that type errors can be excluded at compile time.

References must use the syntax? extends T be explicitly marked as covariant. T is called upper type bound, which is the most common type parameter that is allowed.

ArrayList list; list = new ArrayList (); list = new ArrayList (); list = new ArrayList (); list.set (index, myInteger ); / / Type error by the compiler. ( ( ArrayList ) list ) set (index, myInteger ); / / OK but warning from the compiler: unchecked cast Placing elements in these lists is not possible as this, as described above, not type-safe (exception: null can be stored ). Already at compile time, an error occurs. More generally, the allocation of

Not allowed.

Possibility, however, is the reading of elements:

Number n = list.get (index); / / OK   Integer i = list.get (index); / / Type error: There must be at                                 / / '? extends Number ' not                                 / / Be an integer.   Integer j = ( Integer) list.get (index); / / OK with warning: unchecked cast The assignment

Is thus allowed, but not the allocation

So how arrays Generics offer covariant behavior, but prohibit all operations that are type- unsafe.

Contravariance

Contravariance refers to the behavior of the inheritance hierarchy of the generic type, contrary to the hierarchy of its type parameter. Applied to the example above, this would mean: A list would be assignment-compatible with a list . This is accomplished as follows:

ArrayList list;   list = new ArrayList ();   list = new ArrayList ();   list = new ArrayList (); An object that behaves contravariant must make no assumptions about how an element of type V of T is derived, where T is the type lower bound is (in the example of '? Great Double' T ' Double' ). Therefore it can not be read from the above lists:

Number x = list.get (index); / / Error: 'list' could be of type List   Double x = list.get (index); / / Error: 'list' could List or List be   Object x = list.get (index); / / The only exception: Objects are definitely in the list Not allowed because not type-safe, so the assignment? super T → (derived from Object)

It is not difficult to guess: In return for an element to be stored in such a list:

ArrayList list;   list.Add (new Double (3.0) ); / / OK: 'list' always has the type List                                 / / Or List of . so                                 / / Assigning Double is - > T always allowed. Unrestricted parametric polymorphism

Finally Generics still offer completely polymorphic behavior. This can be made ​​any statement about the type parameter, because it is specified in both directions no limit. But the wildcard is defined. It is represented by a question mark.

ArrayList list;   list = new ArrayList ();   list = new ArrayList ();   list = new ArrayList ();   ... The type parameter itself can not be used here because no statement is possible. Only the assignment T → Object is permitted, since T is definitely an Object. In return, it is guaranteed that the code can work with all the Ts.

Useful can be something, if you work with the generic type:

/ / No information about the type parameters necessary   / / Can '' take '' any lists.   int read size ( List list )   {       return list.size ();   } To illustrate that here wildcards are unnecessary, and it really is not about any variance, following implementation of the above function is specified:

Size int read ( list)   {       return list.size ();   } Web Links

  • Tutorial on Generics in Java - by Ina burner, the author of a book about the Java SCJP Certification ( German )
  • Chapter on generic data types from the Galileo Open Book "Java is an island " ( German )
  • Java ( programming language)
365545

de