Transcript types
Advanced
Java
Programming
Lecture 4
Generic programming
dr hab. Szymon Grabowski
dr inż. Wojciech Bieniecki
[email protected]
http://wbieniec.kis.p.lodz.pl
1
Generics
When you take an element out of a Collection,
you must cast it to the type of element that is stored
in the collection inconvenient and unsafe.
The compiler does not check that your cast is the same
as the collection's type, so the cast can fail at run time.
With generics, the compiler will know the object type
(same for all objects stored), so that it can be checked.
2
Why use generics
When we declare c to be of type Collection<String>, this tells
us something about the variable c that holds true wherever
and whenever it is used,
and the compiler guarantees it (assuming the program
compiles without warnings).
A cast, on the other hand, tells us something the programmer
thinks is true at a single point in the code,
and the VM checks whether the programmer is right only at
run time.
3
Understanding generics
Small excerpt from the definitions of the interfaces List
and Iterator in package java.util:
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
Might seem very similar to C++ templates so far...
4
Understanding generics
...but it is different than C++ templates
In C++, templates are kind of intelligent macros.
Having vector<int> and vector<double> in our program, we also have two
copies of the code: a single copy for each used type (=template
parameter).
In other words, it is a compile-time mechanism.
Not so in Java. There aren’t multiple copies of the code:
not in source, not in binary, not on disk and not in memory.
An analogy to plain methods: parameters in methods are values of a given
type; parameters of generics are types.
5
Understanding generics
A method has formal value parameters that describe the kinds of values it
operates on; a generic declaration has formal type parameters.
When a method is invoked, actual arguments are substituted for the formal
parameters, and the method body is evaluated.
When a generic declaration is invoked, the actual type arguments are
substituted for the formal type parameters.
Consequently...
...the following piece of code:
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
...prints true.
6
Generics in depth
non-generic collections – lots of casts required.
No compile-time checks.
• generic collections – homogeneous, no casts required,
compile-time checking.
7
Definition of generic types
Type variable: “placeholder” for an unknown type.
NOT REALLY A TYPE:
not allowed in new expressions; cannot be derived from.
8
Type parameter bounds
Bounds = supertype of a type variable (Comparable<K> is the
supertype in the example above).
What for? To make available non-static members of a type
variable.
Limitations: gives no access to constructors or static methods.
9
Using generic types
• with concrete type arguments,
• without type arguments (yes!),
• with wildcard arguments.
Concrete instantiation
Raw type (permitted for compatibility – mixing generics with old code)
10
Wildcard instantiation
11
Wildcards
12
Bounded wildcard example
Consider a method that draws objects from a
class hierarchy of shapes.
Cannot draw e.g. a list of circles
because List<Circle> is NOT a subtype of List<Shape>.
13
Bounded wildcard example
Fix with ‘?’ ??
Use upper bound wildcard to solve the problem.
14
Defining a generic type – case study
15
Defining constructors. Naïve approach…
16
Defining constructors.
Quick and dirty fix...
17
Same type constructor argument
18
Problem with the previous example
useful cases are also rejected
Note: the abstract class java.lang.Number is the superclass of
classes Byte, Double, Float, Integer, Long, and Short.
19
Compatible type constructor argument
20
Equivalent implementation
21