Thomas Feiner
LinkedList list = new LinkedList();
list.add(new Integer(0));
Integer i = (Integer)list.get(0);
String s = (String)list.get(0); //not typesafe, fails at runtime
LinkedList<Integer> list = new LinkedList<>(); //diamond operator
list.add(new Integer(0));
Integer i = list.get(0);
String s = list.get(0); //compile time error
public class Pocket<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
public boolean isEmpty() {
return value != null;
}
}
Formal type parameter represented by type variable T
public class MyClass {
public static void main (String[] args) {
Pocket<String> myPocket = new Pocket<>(); //diamond operator
myPocket.set("item1");
System.out.println(myPocket.get());
System.out.println(myPocket.isEmpty());
}
}
Concrete type argument "String".
MyPocket<String> is a parameterized type.
Term | Example |
---|---|
generic type | Pocket<T> |
formal type parameter | T |
parameterized type | Pocket<String> |
actual type parameter | String |
raw type |
Pocket<Pocket<String>> pocketOfPockets = new Pocket<>();
pocketOfPockets.set( new Pocket<String>() );
pocketOfPockets.get().set( "Inner String Pocket" );
System.out.println( pocketOfPockets.get().get() ); // Inner String Pocket
List<List<String>> listOfLists = new ArrayList<>();
public interface Comparable<T> {
public int compareTo(T o);
}
public interface Set<E> extends Collection<E> {
Iterator<E> iterator();
<T> T[] toArray(T[] a);
boolean add(E e);
...
}
non-generic class resolves Generics during implementation
public MyStringComparable implements Comparable<String>
generic class implementing generic interface
public MyComparable<E> implements Comparable<String>
hint: you can also use Void as type parameter
public MyComparable<E> implements Comparable<Void>
Static methods cannot access the actual type parameter
Different methods cannot use different type variables
Solution: Generic Methods
Modifier <type variable(s)> "return type" "method name" "parameters" "throws-clause"
public static <T> void copy(List<T> dest, List<T> src)
public static <T> T random(T first, T second);
Call | Identified types | Common types |
---|---|---|
random("test", 1) | String, Integer | Object, Serializable, Comparable |
random(1L, 1D) | Long, Double | Object, Number, Comparable |
random(new Point(), new StringBuilder() | Point, StringBuilder | Object, Serialiable, Cloneable |
Object s1 = random( "Essen", 1 );
Serializable s2 = random( "Essen", 1 );
Comparable s3 = random( "Essen", 1 );
List<String[]> myList = Arrays.<String[]>asList(new String[] { "A", "B" } );
Improved type inference in Java 8
public class Pocket<T> {
private T value;
public void set( T value ) {
this.value = value;
}
}
public class Pocket {
private Object value;
public void set(Object value ) {
this.value = value;
}
}
Pocket<Integer> p = new Pocket<Integer>(1);
p.set(1);
Integer i = p.get();
Pocket p = new Pocket( 1 );
p.set(1);
Integer i = (Integer) p.get();
List<Number> numbers = new ArrayList<Integer>())
Class<Pocket<String>> pocketClass = Pocket<String>.class;
List myList = new ArrayList();
public static <T extends Comparable<T>> T max( T first, T second )
The common type of first and second has to be "Comparable"
max( 12L, 100F ) ); // Bound mismatch compiler error
Recursive type bound
HashSet<Object> mySet = new HashSet<String>();
If type does not matter (read-only access), use ? wildcard
public static boolean isOnePocketEmpty(Pocket<?>... pockets)
read only, you cannot write!
List<?> myIntegerList = new ArrayList<Integer>();
Object firstNumber = myIntegerList.get(0);
myIntegerList.add(23); // compiler error
Example | Meaning |
---|---|
List<?> myList | List with arbitrary elements |
List<? extends Number> myList | List with numbers or descendants |
Comparator<? super String> | String-, Object- or CharSequence Comparator |
Producer extends, Consumer Super
LESS: lesen extends, schreiben super
public class PecsExample {
public static void main(String[] args) {
List<Integer> src = Arrays.asList(1, 2, 3, 4);
List<Number> dest = new ArrayList<>();
copyList2(src, dest);
dest.stream().forEach(element -> System.out.println(element.intValue()));
}
private static void copyList1(List<? extends Number> src, List<? extends Number> dest) {
for (Number element : src) {
dest.add(element); // compile error
}
}
private static void copyList2(List<? extends Number> src, List<? super Number> dest) {
// src.add(3); // compile error, extends can only be read
for (Number element : src) {
dest.add(element);
}
// Object firstElement = dest.get(0); // super can only be written (returns just Object)
}
}