Mixing generics with legacy code
List<String> words = new ArrayList<String>();
words.add("house");
words.add("book");
addSth(words);
private void addSth(List list) {
list.add(new Integer(6));
}
- the above code compiles (but with warnings) and can work fine, at least to the place of addition (if the object was later retrieved from the
List
it could break down, e.g. words would be treated asList<String>
but Integer objects was retrieved) – this code is unsafe - generic code is only for the compiler purposes; JVM knows nothing about what really the
List
holds - at runtime both legacy and Java 5 code (with generics) look the same, like pre-generic version
List<String> words = new ArrayList<String>();
System.out.println(words instanceof List<String>); // WON'T COMPILE
The above code won’t compile since all instances of a generic class have the same runtime class, regardless of their actual type parameters.
Instead, you should do as below:
List<String> words = new ArrayList<String>();
System.out.println(words instanceof List); // OK
This is also worth a look:
Collection<String> words = new ArrayList<String>();
List<Integer> numbers = new ArrayList<Integer>();
System.out.println(words.getClass() == numbers.getClass()); // produces "true"
Polymorphism and generic methods
class Superclass {}
class Subclass extends Superclass {}
...
List<Superclass> oList = new ArrayList<Subclass>(); // WON'T COMPILE
Superclass [] oArray = new Subclass [5]; // OK
It’s the same with methods:
private void addSth(List<Superclass> list) {}
The above method only accepts List<Superclass>
, there’s no way it acceppts List<Subclass>
The solution:
private void addSth(List<? extends Superclass> list) {}
- it accepts a List holding objects of Superclass type or any of its subtypes (abstract or concrete class) or objects that implement Superclass (in case it’s an interface)
- can’t add anything to the list
private void addSth(List<? super Subclass> list) {}
- it accepts a List holding objects of Subclass type or any other that are of type extended by Subclass
- now the list can be modified (elements can be added)
private void addSth(List<?> list) {} // 1
private void addSth(List<? extends Object> list) {} // 2
private void addSth(List<Object> list) {} // 3
- 1 is the same as 2:
- any type of
List
can be assigned to the argument - nothing can be added to the
List
- any type of
- 3:
- the method accepts only
List<Objects>
- objects can be added to the
List
- the method accepts only
Wildcard notation (?
) cannot be used after new
when a new object is created:
List<?> oList = new List<? extends Superclass>(); // WON'T COMPILE
How to create a generic class and methods?
It’s worth to look at the following examples:
Example 1
public class MyGenericClass <T> {
private T instance;
public T [] oArray;
public MyGenericClass(T instance_p) {
instance = instance_p;
}
public T getInstance() {
return instance;
}
public void setInstance(T instance_p) {
instance = instance_p;
}
}
Example 2
public class MyGenericClass2 {
public <T> void doSth(T instance_p) {
System.out.println("I'm doing sth...");
}
}
Example 3
public class MyGenericClass3 <T, W> {
private T instance;
public W instance2;
}
- T (stands for “type”) can be exchanged with any valid identifier (e.g. E)
- this identifier must be used instead of
?
(which was described earlier) - a generic method can be defined with the type not defined in the class (look at 2nd example above):
public void doSth(T instance_p) {}