Generics Arrays and collections n In Java array

  • Slides: 15
Download presentation
Generics

Generics

Arrays and collections n In Java, array elements must all be of the same

Arrays and collections n In Java, array elements must all be of the same type: n n 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 Array. List, cannot hold primitives, but will accept any type of Object: n n Stack some. Stuff = new Stack(); some. Stuff. push("A String is an Object"); some. Stuff. push(Color. BLUE); We can make an array that, like a collection, holds any Objects: n n 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 n Here’s how to create a type-safe Stack that

Making a collection type safe n Here’s how to create a type-safe Stack that holds only Strings (in Java 1. 4 and earlier): n class Stack. Of. Strings { private Stack internal. Stack = new Stack(); public boolean is. Empty() { return internal. Stack. is. Empty(); } public String push(String s) { internal. Stack. push(s); return s; } public String pop() { return (String)internal. Stack. pop(); } etc.

Generics for type safety in Java 5 n n In Java 5, you can

Generics for type safety in Java 5 n n In Java 5, you can easily make any collection type safe For example, you can create a Stack that holds only Strings as follows: n n Stack<String> names = new Stack<String>(); You can write methods that require a type-safe collection as follows: n void print. Names(Stack<String> names) { n String next. Name = names. pop(); // no casting needed! n names. push("Hello"); // works just the same as before n names. push(Color. RED); // compile-time error!

What generics are and aren’t n n You can almost think of generics as

What generics are and aren’t n n You can almost think of generics as defining new types--for example a Stack<String> is a stack of strings In Java 1. 4, n n In Java 5, String s = my. Stack. pop(); n n String s = my. Stack. pop(); will not compile String s = (String)my. Stack. pop(); compiles, with runtime check my. Stack. push(Color. RED); compiles with no complaint Compiles with no runtime check if my. Stack was declared as Stack<String> Does not compile if my. Stack was declared any other way my. Stack. push(Color. RED); is a compiler error (= syntax error) However, generics are instructions to the compiler only n n 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 CIT 594 n Generics are important in studying data structures because: n

Generics in CIT 594 n Generics are important in studying data structures because: n We make heavy use of Sun’s collections, all of which have been genericized, so we need to know how to use them n n n Genericized collections include: Linked. List, Array. List, Vector, Hash. Set, Tree. Set, Stack, Hash. Map, Tree. Map, Priority. Queue, and others When we create new data structures, n n n 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: n n Generics are only a convenient way to get type safety The data structures themselves have not changed in any way

Using an existing collection n Creation: n n n Assignments: n n n Stack

Using an existing collection n Creation: n n n Assignments: n n n Stack plain. Stack = new Stack(); // the old way Stack s 1 = new Stack<Integer>(); // s 1 is still just a plain stack Stack<Integer> integer. Stack = new Stack<Integer>(); // correct Stack<Integer> s 2 = new Stack(); // works with a warning plain. Stack = integer. Stack; // no problem with this integer. Stack = plain. Stack; // works but is not type safe Use of integer. Stack: n n integer. Stack. push(new Integer(5)); Integer xxx = integer. Stack. pop(); // no cast necessary integer. Stack. push(5); // works, because of autoboxing int x =integer. Stack. pop(); // works, because of auto unboxing

Methods with generics n n n n private static void fiddle(Stack<Integer> ints) { ints.

Methods with generics n n n n private static void fiddle(Stack<Integer> ints) { ints. push(5); } fiddle(integer. Stack); // good call fiddle(plain. Stack); // legal but not type safe fiddle(new Stack<String>()); // not legal static Stack<Integer> my. Method(Stack<Integer> stk) { Stack<Integer> result = new Stack<Integer>(); return result; } Stack<Integer> new. Stack = my. Method(integer. Stack); // good call Stack<Integer> new. Stack 1 = my. Method(plain. Stack); // not safe

Bad news n Type safe? Only sort of. . . n n Stack<Integer> stack

Bad news n Type safe? Only sort of. . . n n Stack<Integer> stack 1 = new Stack<Integer>(); Stack stack 2 = stack 1; // stack 2 is alias of stack 1 stack 2. push(Color. RED); // legal--stack 2 is a plain stack Integer xxx = stack 1. pop(); // Class. Cast. Exception! A little more explanation. . . n n 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 My. Class<T> { T value; // in

Writing your own generic classes public class My. Class<T> { T value; // in this class, use T just like any other type public My. Class(T value) this. value = value; } public void print(T another. Value) { System. out. println(value + " " + another. Value); } }

Iterators n An iterator gives you every element of a collection, one at a

Iterators n An iterator gives you every element of a collection, one at a time n n n The collection has a type iterator(); factory method to return a new iterator to return objects of the given type The method boolean has. Next() 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: n Iterator iter = integer. Stack. iterator(); while (iter. has. Next()) { System. out. println(iter. next()); }

The “enhanced for loop” n Java 5’s new for loop does the iterator work

The “enhanced for loop” n Java 5’s new for loop does the iterator work for you n for (int n : integer. Stack) { System. out. println(n); } is the same (except for the int declaration) as Iterator iter = integer. Stack. iterator(); while (iter. has. Next()) { System. out. println(iter. next()); } n n 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 My. Class<Color>

Subclassing a generic class import java. awt. Color; public class Subclass extends My. Class<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 n n It looks as if generics save you from having to do

Summary n n 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) n This makes your program both more reliable and easier to debug

The End

The End