generics compsci 230 s2 2015 software construction
TRANSCRIPT
Generics
CompSci 230 S2 2015Software Construction
2
Agenda & Reading Topics:
Introduction Fundamentals of generic types Generics & Subtyping Type wildcards
Reading The Java Tutorial:
Generics
09
3
What Are Generics? Generics abstract over Types Classes, Interfaces and Methods can be
Parameterized by Types Generics provide increased readability and type
safety
09
4
Example:Item
Book Movie CD
Priced<<interface
>>
Shirt
public class Item { protected String title; public Item(String title) { this.title = title; } public String getTitle() { return title; }}
public class Book extends Item { private String author; public Book(String title, String author) { super(title); this.author = author; } ... public String toString() { return "Book: '" + ... }}
public class Movie extends Item { private int year; public Movie(String title, int year) { super(title); this.year = year; } ... public String toString() { return ... }}
public class CD extends Item implements Priced { private double price; ... public doublegetPrice() {...}}
public interface Priced { public double getPrice();}
09
5
Interface java.util.List Java’s original specification for list data structures
(non-generic – Java 1.4) This interface defines a contract for each of the operations
of a list, i.e. What it takes in What it returns What the state of the list should be afterwards
Individual implementations should fulfil the contract – in whatever way they see fit
public interface List { public boolean add(Object o); public boolean add(int i, Object); public Object remove(int i); public Object remove(Object o); public Object get(int i); public int indexOf(Object o); public boolean contains(Object o); public int size(); public Iterator iterator(); //plus others}
09
6
Why generics? Type Safety!
Array: We must say what’s in the array
ArrayList: But anything could go in the ArrayList; We can pass in Movie, Book and CD instances as arguments
to add( ) as its formal argument type is Object However because get( )’s return type is Object, we need to
downcast the result to the appropriate subclass
Person[] people = new Person[25]; people[0] = "Sally"; // syntax error
ArrayList people = new ArrayList(); people.add("Sally");
List items = new ArrayList();items.add(new Movie("Psycho",1960));items.add(new Book("LOTR","Toklien"));for (int i = 0; i < items.size(); i++) { Item item = (Item)items.get(i); System.out.println(i+": "+item.getTitle());} 09
7
List of Items We want items to store only objects of type
Item (or its subclasses) What happens if it doesn't? What exactly would happen? Will this compile? Will it run?
items.add(new Movie("Psycho",1960));items.add("Terminator");
for (int i = 0; i < items.size(); i++) { Item item = (Item)items.get(i); System.out.println(i+": "+item.getTitle()); }
Runtime error
Example: TestsApp
09
8
Compile-time vs. Runtime errors Moral of the story: we can’t rely on the
compiler to detect/predict all errors (although we’d like to)
What compilers can detect: Syntactic/”obvious” errors, e.g: accessing an
undeclared variable; calling an undefined method; mismatching braces/brackets; assigning a value to a variable of incompatible type
What compilers can't: Logical errors, unexpected behaviours only
observable at runtime e.g. accessing a null field, bogus user input, nondeterministic code
Most lead to exceptions being thrown like NullPointerException, ArrayIndexOutOfBoundsException, NumberFormatException, ClassCastException
09
9
What can we do instead? Create a specialised List for Item? NO!
Repetitive Inefficient Hardly scalable
public class ItemList { private List items;
public ItemList() { items = new ArrayList(); } ...}
public class StringList { private List items;
public StringList () { items = new ArrayList(); }
public void add(String s) { items.add(s); } ...}
public class IntList { private List items;
public IntList() { items = new ArrayList(); }
public void add(Integer i) { items.add(i); } ...}
09
10
Answer: Generics! With generics, we can make List a generic
type By parameterising List with the type Item we
are guaranteed that any instance of this special List would only contain objects of type T (or its subclasses)
09
11
Example: <String> Instead of saying: List words = new
ArrayList(); You'll have to say:
Replaces runtime type checks with compile-time checks No casting; instead of
String title = (String) words.get(i);you use
Some classes and interfaces that have been “genericized” are: Vector, ArrayList, LinkedList, Hashtable, HashMap, Stack, Queue …
List<String> words = new ArrayList<String>();
String title = words.get(i);
09
12
More Examples The letter E as the type parameter for elements
in generic collections
Examples:
ArrayList<String> words = new ArrayList<String>();ArrayList<Integer> nums = new ArrayList<Integer>();
ArrayList<String> words = new ArrayList<String>();list1.add(new String("HA"));list1.add(new String("HE"));;String s1 = list1.get(0);String s2 = list1.get(1);System.out.println(s1 + " " + s2);
ArrayList<Integer> nums = new ArrayList<Integer>();nums.add(new Integer(4));nums.add(new Integer(5));Integer i1 = nums.get(0);Integer i2 = nums.get(1);
09
13
for-each loop The for-each loop is used to access each
successive value in a collection of values. Syntax:
Example:ArrayList<String> words = new ArrayList<String>();...for (String str : words) { System.out.println(str); }
for (Base_Type var :Collection_Object) Statement;
09
14
Generics and type safety Good news: the compiler can help us prevent
type errors The compiler enforces the parameterised type
List<Item> to only accept and return instances of Item (or its subclasses)
List<Item> genericsItems = new ArrayList<Item>();genericsItems.add(new Movie("Psycho",1960));genericsItems.add("Terminator");
List<Item> genericsItems = new ArrayList<Item>();genericsItems.add(new Movie("Psycho",1960));genericsItems.add(new Book("LOTR","Tolkien"));genericsItems.add(new CD("Ozomatli",2.50));
for (int i = 0; i < genericsItems.size(); i++) { Item item = genericsItems.get(i); System.out.println(i+": "+item.getTitle());}
COMPILE-TIME ERROR
Example: TestGenericsApp
09
15
Generics Vs No Generics
public class Arraylist<E> { private E[] elementData; ... //stuff public boolean add(E o) { elementData[size++] = o; return true; } public E get(int i) { return elementData[i]; }}
public class ArrayList { private Object[] elementData; ... //stuff public boolean add(Object o) { elementData[size++] = o; return true; } public Object get(int i) { return elementData[i]; }}
‘Generic type’
‘Non-generic type’
ArrayList<Item> items = new ArrayList<Item>();
‘Type argument’
‘Parameterised type’
‘Type parameter’
/‘Type variable’
09
16
Example: Comparable + Generics Comparable Interface: java.lang.Comparable
int compareTo() returns an integer result: Returns negative if the object it is applied to is less than the argument Returns zero if the object it is applied to is equal to the argument Returns positive if the object it is applied to is greater than the argument
public interface Comparable { public int compareTo(Object obj);}public class Person implements Comparable {
protected String irdNumber; ... public int compareTo(Object obj) { if (!(obj instanceof Person)) { throw new ClassCastException("Not a Person"); } Person p = (Person) obj; return irdNumber.compareTo(p.getIRD()); } }
without Generics
public class Person implements Comparable<Person> protected String irdNumber; ... public int compareTo(Person p) { return irdNumber.compareTo(p.getIRD()); }}
with Generics
09
17
Generics & Subtyping Is a List of String a List of Object? Is a List of Movie a List of Item?
If this is allowed, then we can add items to the list of Movie by accessing genericsItems
attempt to assign an Item to a Movie object!!!
List<String> ls = new ArrayList<String>();ls.add("Hello");...List<Object> lo = ls;
List<Movie> lm = new ArrayList<Movie>();lm.add(new Movie("Psycho",1960));...genericsItems = lm;
COMPILE-TIME ERROR
COMPILE-TIME ERROR
genericsItems.add(new Item("Sample"));Movie m1 = lm.get(0);
ERROR
09
18
Generics & Subtyping So
Movie is a subtype of Item, and G is some generic type declaration
It is not the case that G<Movie> is a subtype of G<Item>
But We normally think that a List<Driver> is a
List<Person> assuming that Drive is a subtype of Person.
We will need to look at Wildcards!
09
19
Type wildcards Here’s a simple (no generics) method to print out
any list (without generics):
The above still works in Java 1.5, but now it generates warning messages
Next, here is an attempt using Generics
But it only takes a list of Object, but it is not a supertype of all kinds of lists.
public static void printCollection(List c) { for (Iterator i = c.iterator(); i.hasNext(); ) { System.out.println(i.next()); }}
public static void printCollection(List<Object> c) { for (Iterator<Object> i = c.iterator(); i.hasNext(); ) { System.out.println(i.next()); }}
uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for
details.
List mylist = new ArrayList();…printCollection(mylist);
List<Item> mylist = new ArrayList<Item>(); printCollection(mylist); //ERROR 09
20
Type wildcards <?> You should eliminate all errors and warnings in
your final code, so you need to tell Java that any type is acceptable:
<?> (i.e. any type) signifies an unbounded wildcard. (pronounced “list of unknown”)
a list whose element type matches anything = called wildcard type
public static void printCollection(List<?> c) { for (Iterator<?> i = c.iterator(); i.hasNext(); ) { System.out.println(i.next()); }}
List<Movie> movieList = new ArrayList<Movie>();movieList.add(new Movie("Psycho",1960));printCollection(movieList);
List<String> myStrlist = new ArrayList<String>();myStrlist.add("Hello");printCollection(myStrlist);
09
21
for-each statement for(type var : array) {...}
or for(type var : collection) {...}
Example:
public static void printCollection(List<?> c) { for (Object e: c) { System.out.println(e); }}
List<Movie> movieList = new ArrayList<Movie>();movieList.add(new Movie("Psycho",1960));printCollection(movieList);
List<String> myStrlist = new ArrayList<String>();myStrlist.add("Hello");printCollection(myStrlist);
09
22
Subtyping in generics Consider the following method:
The type rules say that the above method can only be called on lists of exactly Item:
It cannot, for instance, be called on a List<Movie> But, how to accept a list of any kind of item (e.g.
List<Movie>, List<Book>)
Item
Movie
public static void printItemCollection(List<Item> il) { for (Item i: il) { System.out.println(i.getTitle()); } }
public static void printItemCollection(List<? extends Item> il) { for (Item i: il) { System.out.println(i.getTitle()); } }
09
23
Bounded Wildcards <? extends T> (i.e. any subclass of T, including T
itself) signifies a bounded wildcard <?> (i.e. any type) signifies an unbounded wildcard Note: <?> is equivalent to <? extends Object>
<? extends Item> => Item is the upper bound of the wildcard
Note that since wildcards denote unknown types, there are limitations on how a wildcard variable can be used It is now illegal to write into the list in the body of the
method Such limitations are compiler enforced
It is an unknown subtype of Item. Since we don’t know what type it is, we don’t know if it is a supertype of Movie; it might or might not be such a supertype, so it isn’t safe to pass a Movie there.
public static void printItemCollection(List<? extends Item> il) { il.add(new Movie("Psycho",1960)); }
COMPILE-TIME ERROR
09