4. A class or interface whose declaration has one or more type parameters is a
generic class or generic interface. (generic type)
Ex :
Generic interface declaration
public interface List<E> extends Collection<E> {
// Bulk of code is emitted
}
Generic class declaration
public class ArrayList<E> extends AbstractList<E> implements List<E>, Random-access,
Cloneable, java.io.Serializable {
// Bulk of code is emitted
}
Generic Types
5. Client Code
1.List<String> dataListWithGenerics = new ArrayList<String>();
// parameterized List
2. List dataListWithoutGenerics = new ArrayList(); // raw type List
Both declarations are legal.
So, what is the difference ?
Number 1 is parameterized type representing List whose element type is
“String”.
Number 2 is raw type representing List whose element type can be any type.
(behave same as List representation before generic is added to the language)
Generic Types
6. public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<E>(s1);
result.addAll(s2);
return result;
}
This is discussed in Item 27
Generic Methods
7. Compiler use process called erasure.
(It erase all the generic type information at compile time)
All the type information betweeen angle brackets is thrown out.
All remaining uses of type variables are replaced by the upper bound of the type variable
(usually Object)
Whenever the resulting code isn’t type-correct, a cast to the appropriate type is inserted
How generics work?
8. How generics work?
public String loophole(Integer x) {
List<String> ys = new LinkedList<String>();
List xs = ys;
xs.add(x); // compile-time unchecked warning
return ys.iterator().next();
}
public String loophole(Integer x) {
List ys = new LinkedList;
List xs = ys;
xs.add(x);
return (String) ys.iterator().next(); // run time error
}
Compiler change the source as follows
9. Let’s take an example :
If client code with raw type is as follows,
private final Collection stamps = new ArrayList() ;
stamps.add(new Coin());
Later if stamps is accessed as follows,
for (Iterator i = stamps.iterator(); i.hasNext(); ) {
Stamp s = (Stamp) i.next();
... // Do something with the stamp
}
// Accidently added code
What is the difference between the raw type
and parameterized type
// Throws ClassCastException
10. private final Collection<Stamp> stamps = new ArrayList<Stamp>() ;
stamps.add(new Coin());
for (Iterator i = stamps.iterator(); i.hasNext(); ) {
Stamp s = i.next();
... // Do something with the stamp
}
// Compile error will arise when you attempt to insert
Coin object to the collection
What happened if you replace raw type with
generics?
// No need to explicit casting, compiler will do that for you
Other benefits
// for-each loop over a parameterized collection - type safe
for (Stamp s : stamps) { // No cast
... // Do something with the stamp
}
// for loop with parameterized iterator declaration - type safe
for (Iterator<Stamp> i = stamps.iterator(); i.hasNext(); ) {
Stamp s = i.next(); // No cast necessary
... // Do something with the stamp
}
11. If you use raw types, you lose all the safety and expressiveness
benefits of generics.
Language provide raw types to support migration compatibility since
there are enormous amount of old codes exists.
It had to be legal to pass instances of parameterized types to methods
that were designed for use with ordinary types, and vice versa.
So instead of using raw types better to use parameterized types like,
List<String>, List<Object>
But there is a sub typing rule to consider.
Although String is a subtype of Object List<String> is not a
subtype of List<Object>
List<String> is a subtype of List
List<String> is a subtype of List<?>
Note
In Item 25 these rules are discussed deeply.
Conclusion
12. You lose type safety if you use a raw type like List, but not if you use
a parameterized type like List<Object>
Ex :
// Uses raw type (List) - fails at runtime
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o); // you get a warning here since this is raw type
}
Best way to use
13. private static void unsafeAdd(List<Object> list, Object o) {
list.add(o);
}
So, you will get a compile time error when try to add new Integer(42) object
to the list. So error can be detected earlier, not at run time.
Anyway the above code doesn’t work, so working version of this code need
to be as follows,
Best way to use
14. Suggestion
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
safeAdd(strings, new Integer(42)); // compile time error detection
String s = strings.get(0);
}
private static <E> void safeAdd(List<E> list, E e) {
list.add(e);
}
Best way to use
15. // Unbounded wildcard type - type safe and flexible
int numElementsInCommon(Set<?> s1, Set<?> s2) {
int result = 0;
for (Object o1 : s1) {
if (s2.contains(o1))
result++;
}
return result;
}
When read data from a source
Actual type of the ? will be detected by the compiler using a technique called
wild card detection.
This will be explained in Item-27 clearly.
16. Benefit of using wildcard
You can’t put any element (other than null) into a Collection<?>
(If you use wildcard declaration, preventing you from corrupting the
collection’s type invariant)
Limitation of the wildcard
If need can’t put any element other than null.
Can’t assume anything about the type of the objects that you get out.
If these restrictions are unacceptable, you can use generic methods (Item 27)
or bounded wildcard types (Item 28)
17. Exceptions (When you must use raw types)
1. You must use raw types in class literals
The specification does not permit the use of parameterized types in class
literals.
List.class, String[].class, and int.class - are all legal
List<String>.class and List<?>.class - are not legal
2. This is the preferred way to use the instanceof operator with generic
types
// Legitimate use of raw type - instanceof operator
if (o instanceof Set) { // Raw type
Set<?> m = (Set<?>) o; // Wildcard type
}
18. Summary
Using raw types can lead to exceptions at runtime, so don’t use them in new
code.
They are provided only for compatibility and interoperability with legacy code
that predates the introduction of generics.
Safe Type Declarations
Set<Object> - Parameterized type representing a set that can contain
objects of any type.
Set<?> - Wildcard type representing a set that can contain only objects
of some unknown type.
Unsafe Type Declaration
Set - Raw type
19. Term Example Item
Parameterized type List<String> Item 23
Actual type parameter String Item 23
Generic type List<E> Items 23, 26
Formal type parameter E Item 23
Unbounded wildcard type List<?> Item 23
Raw type List Item 23
Bounded type parameter <E extends Number> Item 26
Recursive type bound <T extends Comparable<T>> Item 27
Bounded wildcard type List<? extends Number> Item 28
Generic method static <E> List<E> asList(E[] a) Item 27
Type token String.class Item 29
Summary (Cont…) / New terms introduced