40
Generics and Type Safety CS 180 Sunil Prabhakar Department of Computer Science Purdue University Monday, November 16, 2009

Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Generics and Type Safety

CS 180Sunil PrabhakarDepartment of Computer Science Purdue University

Monday, November 16, 2009

Page 2: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

2

Dynamic Data Collections

Already seen several examples of dynamic data Linked list, Stack, Queue, Trees

Java provides a number of such classes part of the Java Foundation Classes (JFC) e.g., Vector, HashMap, ArrayList

An important issue with each of these is creating homogeneous collections e.g., a Stack of Students objects only how can we achieve this?

Why? Type safety.

Monday, November 16, 2009

Page 3: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

3

The Node Class for Strings

class Node { private Node next; private String content;

public Node() { next = null; content = null; } public String getContent(){ return content; } public void setContent(String s){ content = s; } public Node getNext(){ return next; } public void setNext(Node nextNode){ next = nextNode; }}

. . .String s1 = “Hi”;Student student = new Student(“Jane”);

Node stringNode, studentNode;stringNode = new Node();studentNode = new Node();

stringNode.setContent(s1);

studentNode.setContent(student);

s1 = stringNode.getContent();student = studentNode.getContent();. . .

Will not compile!

Monday, November 16, 2009

Page 4: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

4

The Node Class for Students

class Node { private Node next; private Student content;

public Node( ) { next = null; content = null; } public Student getContent(){ return content; } public void setContent( Student s){ content = s; } public Node getNext(){ return next; } public void setNext(Node nextNode){ next = nextNode; }}

. . .String s1 = “Hi”;Student student = new Student(“Jane”);

Node stringNode, studentNode;stringNode = new Node();studentNode = new Node();

stringNode.setContent(s1);

studentNode.setContent(student);

s1 = stringNode.getContent();student = studentNode.getContent();. . .

Will not compile!

Monday, November 16, 2009

Page 5: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Problem

Need a (slightly) different class for each homogeneous collection!

What about the existing JFC classes? If we want a single class, then we are

forced to have Object as the content! Now we are unable to enforce a

homogeneous collection we can add objects of any class to these

collections!5

Monday, November 16, 2009

Page 6: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

6

The General Node Class

class Node { private Node next; private Object content;

public Node( ) { next = null; content = null; } public Object getContent(){ return content; } public void setContent( Object s){ content = s; } public Node getNext(){ return next; } public void setNext(Node nextNode){ next = nextNode; }}

. . .

String s1 = “Hi”;

Student student = new Student(“Jane”);

Node stringNode, studentNode;

stringNode = new Node();

studentNode = new Node();

stringNode.setContent(s1);

studentNode.setContent(student);

s1 = (String) stringNode.getContent();

student = (Student) stringNode.getContent();

. . .

Need to cast!

Exception

Monday, November 16, 2009

Page 7: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Generics

How can we have a single class, yet enforce homogeneity?

Solution: Generics (introduced in Java 1.5) Generics help achieve type safety

enforce homogeneous collections improves compile-time checking and

enforcement of types improves reliability of programs

All JCF classes were retro-fitted to support generics.

7

Monday, November 16, 2009

Page 8: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

The Generic Node class

A generic class takes one (or more) type parameters

The type parameter behaves like an argument that is a type (class)

8

Monday, November 16, 2009

Page 9: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

9

The Generic Node Class

class Node <T> { private Node next; private T content;

public Node( ) { next = null; content = null; } public T getContent(){ return content; } public void setContent( T s){ content = s; } public Node getNext(){ return next; } public void setNext(Node nextNode){ next = nextNode; }}

. . .String s1 = “Hi”;Student student = new Student(“Jane”);

Node <String> stringNode;Node <Student> studentNode;stringNode = new Node <String>();studentNode = new Node <Student>();

stringNode.setContent(s1);studentNode.setContent(string);studentNode.setContent(student);

s1 = stringNode.getContent();

s1 = studentNode.getContent();. . .

Will not compile!

No casting

Monday, November 16, 2009

Page 10: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

10

Generic classes and objects

Depending upon the type specified for the type parameter when creating an object of the Node class, the compiler will perform the appropriate type checking. The content of stringNode can only be a String object

(or descendants) The content of studentNode can only be an object of

class Student (or descendants) This is exactly what we wanted

We define only a single class, and We are able to limit the data types for different

instances.

Monday, November 16, 2009

Page 11: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

11

Generic classes

It is important to realize that there is only one class called Node.

stringNode and studentNode are both of class Node The class is called Node, the constructor is Node(). There are no Node<T>, or Node<String>, …

classes. However, even though they are from the same

class, we cannot use them interchangeably: stringNode = studentNode;

Monday, November 16, 2009

Page 12: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

12

Generic classesNode <String> stringNode = new Node <String> ();

Node <Student> studentNode = new Node <Student> ();

if (stringNode instanceof Node)

System.out.println ("stringNode is a Bag object");

if (stringNode instanceof Node <T>)

System.out.println ("stringNode is a Node<T> object");

if (stringNode instanceof Node <String>)

System.out.println ("stringNode is a Node<String> object");

if (stringNode instanceof Node <Student>)

System.out.println ("stringNode is a Node<Student> object");

Will not compile!

Monday, November 16, 2009

Page 13: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

13

Primitive data

A type parameter can only take a class data type. If we want to store primitive data in our Bag, then

we have to convert it to its corresponding wrapper class.

With Java 5 this is trivial due to autoboxing and auto unboxing.

Node<Integer> intNode = new Node<Integer>();

int i = 5, j;intNode.store(new Integer(i));intNode.store(i);j = intNode.retrieve();j = intNode.retrieve().intValue();

Monday, November 16, 2009

Page 14: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

14

Multiple Type Parameters

We can have multiple type parameters in a generic class.

class MapNode<T1, T2>{

private T1 key;

private T2 content;

private MapNode next;

public MapNode(T1 k, T2 item, MapNode n){

storeKey(k);

storeContent(item);

next = n;

}

public T1 retrieveKey(){

return key;

}

public T2 retrieveContent(){

return content;

}

public void store(T1 k, T2 item){

key = k;

content = item;

}

}

Monday, November 16, 2009

Page 15: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

15

ExampleMapNode<String, Student> mapList = null;

String id = new String(“23423”);

Student st = new Student(“Jane”);

mapList = new MapNode<String, Student> (id, st, mapList);

String s1 = mapList.retrieveKey();

Student st1 = mapList.retrieveContent();

s1 = mapList.retrieveContent();

st1 = mapList.retrieveKey();

Will not compile!

Monday, November 16, 2009

Page 16: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

16

Example

DualBag<Book, Book> pair =

new DualBag<Book, Book> ();

Book b1 = new Book();

Book b2 = new Book();

parr.storeFirst(b1);

pair.storeSecond(b2);

Both parameters can be of the same type.

class DualBag<T>{

private T content1;

private T content2;

public DualBag(){

storeFirst(null);

storeSecond(null);

}

public DualBag(T item1, T item2){

storeFirst(item1);

storeSecond(item2);

}

public T retrieveFirst(){

return content1;

}

public T retrieveSecond(){

return content2;

}

public void storeFirst(T item){

content1 = item;

}

public void storeSecond(T item){

content2 = item;

}

}

If we want to enforce this then we use only one parameter.

Monday, November 16, 2009

Page 17: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

17

Type Safetyclass BagA{

private Object content;

public BagA(){

store(null) ;

}

public Object retrieve(){

return content;

}

public void store(Object item){

content = item;

}

}

class BagB<T>{

private T content;

public BagB(){

store(null) ;

}

public T retrieve(){

return content;

}

public void store(T item){

content = item;

}

}

These two are not the same. Only the generic class offers (compile time) type

safety. The other may lead to runtime errors due to type

mismatches.

Monday, November 16, 2009

Page 18: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

18

Type Safety

Which is better Have the compiler enforce type safety or Allow unsafe expressions and then have a runtime

error? It is far better to catch such errors (which are

likely to be logical errors) at compile time. Thus type safety is desirable.

In addition to better reliability, note that with type safety there is no need for type casting or runtime type checking. This can improve the runtime of programs too.

Monday, November 16, 2009

Page 19: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Quiz

What is the class of variable numNode?A. Node<Number>B. Node<Integer>C. Node<T>D. Node

19

Node <T> numNode = new Node <Number> ();

Node <Integer> intNode = new Node <Integer> ();

numNode = intNode;

class Node<T>{

...

}

Monday, November 16, 2009

Page 20: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

20

Bounded Types

The current generic version of Node allows us to create instances to store any type of objects as content.

What if we want to limit the types of objects that can be stored in our Node?

We can do this by bounding the type parameter.

Consider a Node class that only allows us to store numeric objects.

Monday, November 16, 2009

Page 21: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

21

Bounded Type

class NumBag<T extends Number>{

private T content;

public NumBag(){

store(null) ;

}

public NumBag(T item){

store(item) ;

}

public T retrieve(){

return content;

}

public void store(T item){

content = item;

}

}

NumBag <Double> doubleBag = new

NumBag <Double> ();

NumBag <Laptop> laptopBag = new

NumBag <Laptop> ();

NumBag <Number> numBag;

doubleBag.store(new Double(3.0));

numBag.store(new Number(12));

numBag.store(new Integer(12));

numBag = new NumBag<Double>();

Will not compile!Laptop doesn’t

extend NumberNumber is an abstract class!No super-sub relationship!

Monday, November 16, 2009

Page 22: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

22

Wildcard types

Suppose we would like to be able to check for equality of the number values stored in different instances of the NumBag class:

NumBag<Double> bag1= new NumBag<Double>(new Double(3.0));NumBag<Integer> bag2 = new NumBag<Integer>(new Integer(3));if(bag1.isSameValue(bag2)) System.out.println(“The values are the same.”);

How should the isSameValue method be written? Note that it may be called on an object such as

bag1 that stores doubles and receive an object such as bag2 that stores integers as a parameter.

Monday, November 16, 2009

Page 23: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

23

NumBag<Double> bag1= new NumBag<Double>(new Double(3.0));NumBag< Integer> bag2 = new NumBag< Integer>(new Integer(3));

if(bag1.isSameValue(bag2)) System.out.println(“The values are the same.”);

Wildcard types

class NumBag<T extends Number>{

private T content;

. . .

public boolean isSameValue(NumBag<T> item){

return this.retrieve().doubleValue() ==

item.retrieve().doubleValue();

}

}

Will not compile!

Monday, November 16, 2009

Page 24: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

24

Wildcard types

class NumBag<T extends Number>{

private T content;

. . .

public boolean isSameValue(NumBag<?> item){

return this.retrieve().doubleValue() ==

item.retrieve().doubleValue();

}

}

Okay as long as bag2’s content supports the doubleValue() method

NumBag<Double> bag1= new NumBag<Double>(new Double(3.0));NumBag< Integer> bag2 = new NumBag< Integer>(new Integer(3));

if(bag1.isSameValue(bag2)) System.out.println(“The values are the same.”);

Monday, November 16, 2009

Page 25: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

25

Limitations of generics

We are not allowed to Create an instance of the type parameter class

within the generic class, or Use type parameters with static data members

or static methods. The reason is that the actual type

corresponding to the type parameter is known only when an object is instantiated.

Monday, November 16, 2009

Page 26: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

26

Example

class NumBag<T extends Number>{

private T content;

private static T classContent;

public NumBag(){

content = new T();

store(content) ;

}

public static T getClassContent(){

return classContent;

}

Will not compile!

Monday, November 16, 2009

Page 27: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

27

Java Collections Framework

The JCF provides a large set of very commonly used classes such as ArrayList, Vector, Queue, …

In earlier releases of Java the JCF classes were unable to enforce types strongly.

All JCF classes have been retrofitted in Java 5 to work correctly with generics.

These classes are defined in java.util

Monday, November 16, 2009

Page 28: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

28

(Old) JCF Example

import java.util.*;

List bookList = new ArrayList();

booklist.add(new Book(“Wilder”);

booklist.add(new Book(“Nabokov”);

booklist.add(new Book(“William”);

bookList.add(“Shakespeare”);

Iterator itr = bookList.iterator();

while(itr.hasNext()){

Book book = (Book) itr.Next();

System.out.println(book.getAuthor());

}

Can add any type of objectto this ArrayList.

Note the need for typecasting.

Monday, November 16, 2009

Page 29: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

29

Generics JCF Example

import java.util.*;

ArrayList<Book> bookList = new ArrayList<Book>();

booklist.add(new Book(“Wilder”);

booklist.add(new Book(“Nabokov”);

booklist.add(new Book(“William”);

bookList.add(“Shakespeare”);

Iterator<Book> itr = bookList.iterator();

while(itr.hasNext()){

Book book = itr.Next();

System.out.println(book.getAuthor());

}

Compile error.

Iterator needs type too.

No need for typecasting.

Monday, November 16, 2009

Page 30: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

30

New for statement

Java 5 has also introduced a new variant of the for loop statement: for-each loop

Eliminates the need for iterator objects for iterating through a collection.

for(Book book : bookList) { System.out.println(book.getAuthor());}

General format: for (<type> <var> : <collection>) <stmt>

Collection must be a JCF class and type must match the type of the collection.

Monday, November 16, 2009

Page 31: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

31

for-each Example with ArrayList

ArrayList<String> myList = new ArrayList<String>();

myList.add(“Qian”);

myList.add(“Achebe”);myList.add(“Lisa”);

for(String str : myList) { System.out.println(str);

}

Monday, November 16, 2009

Page 32: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

32

for-each Example with arraysint number[] = {1, 3, 4, 5, 6 9};

int sum = 0;

for(int element : number) {

sum += element;

}

int sum = 0;

for (int i = 0; i< number.length; i++){

sum += number[i];

}

NOTE: not allowed to change the value of loop variable

of a for-each loop.

Monday, November 16, 2009

Page 33: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

33

Non-generic ArrayList example

ArrayList myList = new ArrayList();

myList.add(“Qian”);

myList.add(“Achebe”);

myList.add(“Lisa”);

for(Object b : myList) {

System.out.println(“Item is ” + (String)b );

}

Monday, November 16, 2009

Page 34: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

34

Raw Types & Backward Compatibility

All the JCF class have been redefined to be generic classes.

What about earlier programs not written for Java 5 using older JCF classes?

In order to ensure backward compatibility, Java 5 allows a generic class to be created without specifying a type parameter!

Essentially, the compiler assumes that the type is Object -- thus any class can be stored.

If we don’t specify the type, we get a raw type. Raw types do not have the benefit of type safety

and should be avoided.

Monday, November 16, 2009

Page 35: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

35

Arrays and generics

Arrays should not be used with generics unless you wish to use raw types.

Instead use the ArrayList or LinkedList class to create a generic array.

In general, do not use raw types with generics.

Their use is only for ensuring backward compatibility in legacy code written before Java 5.

Monday, November 16, 2009

Page 36: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

36

Raw Types

Bag bag = new Bag();

bag.store(new Integer(5));

bag.store(“test”);

bag.store(new Book(“Ludlum”));

Bag rawBag = new Bag();

Bag<String> strBag = new Bag<String>;

Bag<Integer> intBag = new Bag<Integer>;

intBag.store(new Integer(5));

rawBag = intBag;

strBag = rawBag;

String str = strBag.retrieve();

Dangerous, but allowed!

Monday, November 16, 2009

Page 37: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Limitations of Generics Cannot create a generic class for

Exceptions Anonymous inner classes

classes defined within another class, but with no name.

E.g. as Action Handlers for GUIs Enum types

http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Casting to a generic type generates a warning (“unchecked cast”) cast is to the raw type (with no type

parameter) 37

Monday, November 16, 2009

Page 38: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

No Inheritance for Generics

List<Object> is not a super-type of List<Number>

However, List<Number> is a super-type of ArrayList<Number> !!!!This only works if the type parameter is the same.

Note that arrays behave differently: Object[] is a super-type to Number[]

38

Monday, November 16, 2009

Page 39: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

Lots of subtleties with Generics

See http://www.AngelikaLanger.com/GenericsFAQ/JavaGenericsFAQ.html for an excellent treatment of generics in Java.

39

Monday, November 16, 2009

Page 40: Generics and Type Safety - Purdue Universitycs180/Fall2009Web/lecture...Generics How can we have a single class, yet enforce homogeneity? Solution: Generics (introduced in Java 1.5)

40

Generics, Inheritance & Interfaces

It is possible to define a generic subclass of a non-generic class.

It is also possible to define a subclass of a generic class IMPORTANT: in this case the subclass must also be

generic, or fix the type parameter It is possible for a generic class to implement a

non-generic interface. It is also possible for a class to implement a

generic interface IMPORTANT: in this case the class must also be

generic,or fix the type parameter

Monday, November 16, 2009