Transcript 09Genericsx
CompSci 230 S1 2016
Software Construction
Generics
Agenda & Reading
Topics:
Introduction
Fundamentals of generic types
Generics & Subtyping
Type wildcards
Reading
The Java Tutorial:
2
Generics
09
What Are Generics?
3
Generics abstract over Types
Classes, Interfaces and Methods can be Parameterized by
Types
Generics provide increased readability and type safety
09
Item
Example:
public class Item {
protected String title;
public Item(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
Book
Movie
Priced
<<interface>
>
CD
Shirt
public interface Priced {
public double getPrice();
}
public class CD extends Item implements Priced {
private double price;
...
public doublegetPrice() {...}
}
public class Movie extends Item {
private int year;
public Movie(String title, int year) {
super(title);
this.year = year;
}
...
public String toString() {
return ...
}
}
4
public class Book extends Item {
private String author;
public Book(String title, String author) {
super(title);
this.author = author;
}
...
public String toString() {
return "Book: '" + ...
}
}
09
Interface java.util.List
Java’s original specification for list data structures
This interface defines a contract for each of the operations of a list,
i.e.
5
(non-generic – Java 1.4)
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
public
public
public
public
public
public
public
public
//plus
}
boolean add(Object o);
boolean add(int i, Object);
Object remove(int i);
Object remove(Object o);
Object get(int i);
int indexOf(Object o);
boolean contains(Object o);
int size();
Iterator iterator();
others
09
Why generics?
Type Safety!
Array:
6
We must say what’s in the array
ArrayList:
Person[] people = new Person[25];
people[0] = "Sally"; // syntax error
ArrayList people = new ArrayList();
people.add("Sally");
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
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
Example: TestsApp
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?
Runtime
error
7
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());
}
09
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:
What compilers can't:
8
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
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
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 IntList {
private List items;
public class StringList
private List items;
public StringList () {
items = new ArrayList();
}
public IntList() {
items = new ArrayList();
}
9
public void add(Integer i) {
items.add(i);
}
...
}
{
public void add(String s) {
items.add(s);
}
...
}
09
Answer: Generics!
10
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
Example: <String>
Instead of saying: List words = new ArrayList();
You'll have to say:
List<String> words = new ArrayList<String>();
Replaces runtime type checks with compile-time checks
No casting; instead of
String title = (String) words.get(i);
you use
String title = words.get(i);
11
Some classes and interfaces that have been “genericized” are:
Vector, ArrayList, LinkedList, Hashtable, HashMap, Stack,
Queue …
09
More Examples
The letter E as the type parameter for elements in generic
collections
ArrayList<String> words = new ArrayList<String>();
ArrayList<Integer> nums = new ArrayList<Integer>();
Examples:
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);
12
09
for-each loop
The for-each loop is used to access each successive value in a
collection of values.
Syntax:
for (Base_Type var :Collection_Object)
Statement;
Example:
ArrayList<String> words = new ArrayList<String>();
...
for (String str : words) {
System.out.println(str);
}
13
09
Example: TestGenericsApp
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)
COMPILE-TIME
ERROR
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());
}
14
09
Generics Vs No Generics
‘Generic type’
‘Type parameter’
/‘Type variable’
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];
}
}
‘Non-generic type’
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];
}
}
‘Parameterised type’
ArrayList<Item> items = new ArrayList<Item>();
‘Type argument’
15
09
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 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
16
public interface Comparable {
public int compareTo(Object obj);
}
with Generics
public class Person implements Comparable<Person>
protected String irdNumber;
...
public int compareTo(Person p) {
return irdNumber.compareTo(p.getIRD());
}
}
09
Generics & Subtyping
Is a List of String a List of Object?
Is a List of Movie a List of Item?
COMPILE-TIME
ERROR
COMPILE-TIME
ERROR
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;
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!!!
genericsItems.add(new Item("Sample"));
Movie m1 = lm.get(0);
17
ERROR
09
Generics & Subtyping
So
But
18
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>
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
Type wildcards
List mylist = new ArrayList();
…
printCollection(mylist);
Here’s a simple (no generics) method to print out any list (without
generics):
public static void printCollection(List c) {
for (Iterator i = c.iterator(); i.hasNext(); ) {
System.out.println(i.next());
}
}
uses unchecked or unsafe
operations.
Note: Recompile with Xlint:unchecked for details.
The above still works in Java 1.5, but now it generates warning messages
Next, here is an attempt using Generics
public static void printCollection(List<Object> c) {
for (Iterator<Object> i = c.iterator(); i.hasNext(); ) {
System.out.println(i.next());
}
}
19
But it only takes a list of Object, but it is not a supertype of all kinds of lists.
List<Item> mylist = new ArrayList<Item>();
printCollection(mylist); //ERROR
09
Type wildcards <?>
You should eliminate all errors and warnings in your final code, so
you need to tell Java that any type is acceptable:
public static void printCollection(List<?> c) {
for (Iterator<?> i = c.iterator(); i.hasNext(); ) {
System.out.println(i.next());
}
}
<?> (i.e. any type) signifies an unbounded wildcard. (pronounced “list of
unknown”)
a list whose element type matches anything = called wildcard type
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);
20
09
for-each statement
for(type var : array) {...}
or for(type var : collection) {...}
public static void printCollection(List<?> c) {
for (Object e: c) {
System.out.println(e);
}
}
Example:
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);
21
09
Subtyping in generics
Consider the following method:
public static void printItemCollection(List<Item> il) {
for (Item i: il) {
System.out.println(i.getTitle());
}
}
Item
Movie
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>)
public static void printItemCollection(List<? extends Item> il) {
for (Item i: il) {
System.out.println(i.getTitle());
}
}
22
09
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
public static void printItemCollection(List<? extends Item> il) {
il.add(new Movie("Psycho",1960));
}
23
COMPILE-TIME
ERROR
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.
09