Download CITS2210 Object-Oriented Programming Topic 9 Java: Generics

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
CITS2210
Object-Oriented Programming
Topic 9
Java:
Generics
Summary: Generics allow code to be written that is parameterized with
respect to one or more types. This allows a class or method to be used
uniformly for all object types, or where appropriate for all subtypes of a
particular type.
1
The Motivation for Generics
Suppose we want to write a class ArrayPlus that works like an array, but
has extra methods.
–
We may want methods such as “delete an element and shuffle the rest”.
public class ArrayPlus {
private String[] array;
private int num = 0;
}
public ArrayPlus(int maxSize) {
array = new String[maxSize];
}
public void add(String e) { array[num++]=e; }
public String get(int pos) { return array[pos]; }
public void delete(int pos) {
for(int i=pos; i<num-1; i++)
array[i] = array[i+1];
num--;
}
–
But this class only works for strings!
–
We don't want to copy the code for each type for which we need arrays.
–
What can we do?
2
A Second Attempt: Using the type “Object”
If we want only one version, then why not use Object as the type?
public class ArrayPlus {
private Object[] array;
private int num = 0;
}
public ArrayPlus(int maxSize) {
array = new Object[maxSize];
}
public void add(Object e) { array[num++]=e; }
public Object get(int pos) { return array[pos]; }
public void delete(int pos) {
for(int i=pos; i<num-1; i++)
array[i] = array[i+1];
num--;
}
This will allow us to store any object, which is what we wanted to do.
–
Primitive types like int and float aren't objects, but can be “boxed” into
object types like Integer and Float automatically. See:
http://java.sun.com/j2se/1.5.0/docs/guide/language/autoboxing.html
3
Issues with the second attempt
But, suppose we use this class to store strings.
–
When we retrieve using get, the return type is always Object.
–
The code retrieving will expect a string.
–
So we'll have to cast to use the result as a string.
((String)myArrayPlus.get(3)).substr(1,3)
But, casts are ugly and error prone.
–
If we accidentally cast to wrong type we'll get a runtime error.
–
If we accidentally add something that isn't a string, ditto.
–
–
When a variable has type ArrayPlus it's not obvious what kind of
objects it's supposed to hold.
If we consider array types like String[], they don't have these
problems.
4
The Solution: Generics
These issues motivated the introduction of generics into Java in version
1.5 (now usually just called version 5).
–
Prior to this the previous solution was widely used, and found
unsatisfactory in practice.
Generics are a way of parameterizing interfaces, classes and methods with
respect to types.
–
–
This means that interfaces, classes and methods can have type
parameters.
E.g., this allows the type of elements in an ArrayPlus to be specified.
public class ArrayPlus<E> {
private ELEM[] array;
private int num = 0;
}
public ArrayPlus(int maxSize) {
array = (E[])new Object[maxSize];
}
public void add(E e) { array[num++]=e; }
public E get(int pos) { return array[pos]; }
public void delete(int pos) {
for(int i=pos; i<num-1; i++)
array[i] = array[i+1];
num--;
}
5
Generic parameters
The type parameters in generics are like parameters in methods.
–
–
The types aren't specified in the generic class/interface/method
definitions.
Each time these definitions are used, a particular type is supplied.
Conventions type parameters are usually single capital letter variables,
with the following in standard usage.
E - Element (used extensively by the Java Collections Framework)
• K - Key
• N - Number
• T - Type
• V - Value
S,U,V etc. - 2nd, 3rd, 4th types
•
6
Generics examples
–
Methods may also have type parameters.
–
“Bounds” can also be given for type parameters
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.add(new Integer(10));
integerBox.inspect(20);
}
To specify additional interfaces that must be implemented,
use the & character, as in:
<U extends Number & MyInterface>
7
Subtyping for generics
Are Box<Integer> and Box<Double> subtypes of Box<Numeric>?
It turns out no!
Understanding why becomes much easier if you think of tangible objects
— things you can actually picture — such as a cage:
// A cage is a collection of things, with bars to keep
// them in.
interface Cage<E> extends Collection<E>;
A lion is a kind of animal, so Lion would be a subtype of Animal:
interface Lion extends Animal {}
Lion king = ...;
Where we need some animal, we're free to provide a lion:
Animal a = king;
A lion can of course be put into a lion cage:
Cage<Lion> lionCage = ...;
lionCage.add(king);
and a butterfly into a butterfly cage:
interface Butterfly extends Animal {}
Butterfly monarch = ...;
Cage<Butterfly> butterflyCage = ...;
butterflyCage.add(monarch);
8
Subtyping for generics
But what about an "animal cage"? English is ambiguous, so to be precise
let's assume we're talking about an "all-animal cage":
Cage<Animal> animalCage = ...;
This is a cage designed to hold all kinds of animals, mixed together. It
must have bars strong enough to hold in the lions, and spaced closely
enough to hold in the butterflies. Such a cage might not even be feasible
to build, but if it is, then:
animalCage.add(king);
animalCage.add(monarch);
Since a lion is a kind of animal (Lion is a subtype of Animal), the
question then becomes, "Is a lion cage a kind of animal cage?
Is Cage<Lion> a subtype of Cage<Animal>?". By the above
definition of animal cage, the answer must be "no"!
9