Generics Slides
Download
Report
Transcript Generics Slides
Generics
28-Mar-16
Arrays and collections
In Java, array elements must all be of the same type:
Hence, arrays are type safe: The compiler will not let you put the
wrong kind of thing into an array
A collection, such as a Vector or ArrayList, cannot hold
primitives, but will accept any type of Object:
Stack someStuff = new Stack();
someStuff.push("A String is an Object");
someStuff.push(Color.BLUE);
We can make an array that, like a collection, holds any Objects:
int[] counts = new int[10];
String[] names = { "Tom", "Dick", "Harry" };
Object[ ] whatever = new Object[100];
Prior to Java 5, there was no easy way to make a collection type
safe
Making a collection type safe
Here’s how to create a type-safe Stack that holds only Strings (in
Java 1.4 and earlier):
class StackOfStrings {
private Stack internalStack = new Stack();
public boolean isEmpty() {
return internalStack.isEmpty();
}
public String push(String s) {
internalStack.push(s);
return s;
}
public String pop() {
return (String)internalStack.pop();
}
etc.
Generics for type safety in Java 5
In Java 5, you can easily make any collection type safe
For example, you can create a Stack that holds only
Strings as follows:
Stack<String> names = new Stack<String>();
You can write methods that require a type-safe
collection as follows:
void printNames(Stack<String> names) {
String nextName = names.pop(); // no casting needed!
names.push("Hello"); // works just the same as before
names.push(Color.RED); // compile-time error!
What generics are and aren’t
You can almost think of generics as defining new types--for
example a Stack<String> is a stack of strings
In Java 1.4,
In Java 5, String s = myStack.pop();
String s = myStack.pop(); will not compile
String s = (String)myStack.pop(); compiles, with runtime check
myStack.push(Color.RED); compiles with no complaint
Compiles with no runtime check if myStack was declared as
Stack<String>
Does not compile if myStack was declared any other way
myStack.push(Color.RED); is a compiler error (= syntax error)
However, generics are instructions to the compiler only
You can still say: if (thing instanceof Stack) ...
but you cannot say: if (thing instanceof Stack<String>) ...
This is called erasure--the type information is “erased” at runtime
Generics in CIT594
Generics are important in studying data structures because:
We make heavy use of Sun’s collections, all of which have been
genericized, so we need to know how to use them
Genericized collections include: LinkedList, ArrayList, Vector, HashSet,
TreeSet, Stack, HashMap, TreeMap, PriorityQueue, and others
When we create new data structures,
However, non-genericized collections continue to work
In Java 5, it is almost always a good idea to genericize them
However, Java 5 programs will only work for users who have upgraded their
Java systems--so we may wish to compile for older versions
Generics are not important in data structures because:
Generics are only a convenient way to get type safety
The data structures themselves have not changed in any way
Using an existing collection
Creation:
Assignments:
Stack plainStack = new Stack(); // the old way
Stack s1 = new Stack<Integer>(); // s1 is still just a plain stack
Stack<Integer> integerStack = new Stack<Integer>(); // correct
Stack<Integer> s2 = new Stack(); // works with a warning
plainStack = integerStack; // no problem with this
integerStack = plainStack; // works but is not type safe
Use of integerStack:
integerStack.push(new Integer(5));
Integer xxx = integerStack.pop(); // no cast necessary
integerStack.push(5); // works, because of autoboxing
int x =integerStack.pop(); // works, because of auto unboxing
Methods with generics
private static void fiddle(Stack<Integer> ints) {
ints.push(5);
}
fiddle(integerStack); // good call
fiddle(plainStack); // legal but not type safe
fiddle(new Stack<String>()); // not legal
static Stack<Integer> myMethod(Stack<Integer> stk) {
Stack<Integer> result = new Stack<Integer>();
return result;
}
Stack<Integer> newStack = myMethod(integerStack); // good call
Stack<Integer> newStack1 = myMethod(plainStack); // not safe
Bad news
Type safe? Only sort of...
Stack<Integer> stack1 = new Stack<Integer>();
Stack stack2 = stack1; // stack2 is alias of stack1
stack2.push(Color.RED);// legal--stack2 is a plain stack
Integer xxx = stack1.pop(); // ClassCastException!
A little more explanation...
Java 5 is upwardly compatible with Java 1.4--that is, old programs must
continue to work
Hence you can have non-generic stacks (and stack assignment)
When you use a generic collection, you should make it generic
everywhere, not just in the places that Java would otherwise report an error
Eclipse will provide warnings for many unsafe cases, so pay close
attention to those warnings!
Writing your own generic classes
public class MyClass<T> {
T value; // in this class, use T just like any other type
public MyClass(T value)
this.value = value;
}
public void print(T anotherValue) {
System.out.println(value + " " + anotherValue);
}
}
Iterators
An iterator gives you every element of a collection, one at a time
The collection has a type iterator(); factory method to return a new
iterator to return objects of the given type
The method boolean hasNext() tells you if there are more objects
The method type next() returns the next object
The method void remove() deletes the last object gotten
Example:
Iterator iter = integerStack.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
The “enhanced for loop”
Java 5’s new for loop does the iterator work for you
for (int n : integerStack) {
System.out.println(n);
}
is the same (except for the int declaration) as
Iterator iter = integerStack.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
The enhanced for loop can also be used for arrays, and for any
class you write that implements the Iterator interface
The enhanced for loop is convenient but less powerful than the
old-style for loop, since it just goes through every element in a
forward direction only
Subclassing a generic class
import java.awt.Color;
public class Subclass extends MyClass<Color> {
// You almost always need to supply a constructor
public Subclass(Color color) {
super(color);
}
public static void main(String[ ] args) {
Subclass sc = new Subclass(Color.GREEN);
sc.print(Color.WHITE);
}
}
Summary
It looks as if generics save you from having to do
casting, at the expense of more work in the
declarations
The real benefit is that they replace run-time checks
(and run-time errors) with compile-time checks (and
syntax errors)
This makes your program both more reliable and easier to
debug
The End