+ All Categories
Home > Documents > 1 CS3240 - Generics L. Grewe 2 What is Generics? Data Structures that contain data (such as lists)...

1 CS3240 - Generics L. Grewe 2 What is Generics? Data Structures that contain data (such as lists)...

Date post: 21-Dec-2015
Category:
View: 222 times
Download: 0 times
Share this document with a friend
Popular Tags:
30
1 CS3240 - Generics CS3240 - Generics L. Grewe L. Grewe
Transcript

11

CS3240 - GenericsCS3240 - Generics

L. GreweL. Grewe

22

What is Generics?What is Generics? Data Structures that contain data (such as lists) Data Structures that contain data (such as lists)

are not defined to operate over a specific type of are not defined to operate over a specific type of data; instead, they operate over a homogeneous data; instead, they operate over a homogeneous set, where the set type is defined at declaration. set, where the set type is defined at declaration.

Helps with Reusability (no longer need multiple Helps with Reusability (no longer need multiple data structures to hold different types of data)data structures to hold different types of data)

Helps control run-time errors if you instead could Helps control run-time errors if you instead could have data structures containing different have data structures containing different (heterogeneous) kinds of data.(heterogeneous) kinds of data.

33

Concept in other languagesConcept in other languages

e.g. C++ e.g. C++

In C++, would write generic stack In C++, would write generic stack class using templatesclass using templates

template <type t> class Stack {template <type t> class Stack {

private: t data; Stack<t> * next;private: t data; Stack<t> * next;

public: void push (t* x) { … }public: void push (t* x) { … }

t* pop ( ) { … } t* pop ( ) { … }

};};

44

Java Generic ProgrammingJava Generic Programming Java has class ObjectJava has class Object

• Supertype of all object typesSupertype of all object types• This allows “subtype polymorphism”This allows “subtype polymorphism”

Can apply operation on class T to any subclass S <: TCan apply operation on class T to any subclass S <: T Java 1.0 – 1.4 did not have generics Java 1.0 – 1.4 did not have generics

• No parametric polymorphismNo parametric polymorphism• Many considered this the biggest deficiency of JavaMany considered this the biggest deficiency of Java

Java type system does not let you “cheat”Java type system does not let you “cheat”• Can cast from supertype to subtypeCan cast from supertype to subtype• Cast is checked at run timeCast is checked at run time

55

Run-Time Error without GenericsRun-Time Error without Generics Example from sun.java.com: In the first example (lines 13 to 20), you might believe you're working with a list of Example from sun.java.com: In the first example (lines 13 to 20), you might believe you're working with a list of

Integer objects, when in reality it's a list of Strings. In the second example (lines 11 and 22 to 27), you might Integer objects, when in reality it's a list of Strings. In the second example (lines 11 and 22 to 27), you might think you're working with a homogenous set of String, but this is a heterogeneous set of both String and Integer think you're working with a homogenous set of String, but this is a heterogeneous set of both String and Integer elements. So unless you create a new list subclass for every element type (which would undermine the elements. So unless you create a new list subclass for every element type (which would undermine the advantages of OO reuse), there's no way to statically constrain the list to a set of homogeneous elements. And advantages of OO reuse), there's no way to statically constrain the list to a set of homogeneous elements. And in this simple example, the errors are fairly easy to catch. In a bigger program, you'd have even bigger in this simple example, the errors are fairly easy to catch. In a bigger program, you'd have even bigger problems. problems.

     1.1.  2.  List stringList  = new LinkedList();  2.  List stringList  = new LinkedList();  3.  List integerList = new LinkedList();  3.  List integerList = new LinkedList();  4.   4.   5.  integerList.add(new Integer(1));  5.  integerList.add(new Integer(1));  6.  integerList.add(new Integer(2));  6.  integerList.add(new Integer(2));  7.   7.   8.  stringList.add(new String("I am a String"));  8.  stringList.add(new String("I am a String"));  9.   9.   10.   10. // Nothing constrains the elements to a homogeneous set.// Nothing constrains the elements to a homogeneous set.  11. stringList.add(new Integer(1));  11. stringList.add(new Integer(1));  12.   12.   13. Iterator listIterator = integerList.iterator();  13. Iterator listIterator = integerList.iterator();  14.   14.   15.   15. // Compiler unaware of the list's return type and the illegal cast.// Compiler unaware of the list's return type and the illegal cast.  16.   16. // Developer meant to iterate through the string list.// Developer meant to iterate through the string list.  17. while(listIterator.hasNext()) {  17. while(listIterator.hasNext()) {  18.   18.   19.     19.   // Illegal cast caught at runtime// Illegal cast caught at runtime..  20.   String item = (String)listIterator.next();  20.   String item = (String)listIterator.next();  21. }  21. }  22.   22.   23. listIterator = stringList.iterator();  23. listIterator = stringList.iterator();  24.   24. // No guarantee of homogeneous containers.// No guarantee of homogeneous containers.  25. while (listIterator.hasNext()) {  25. while (listIterator.hasNext()) {  26.    26.   // fail at runtime due to heterogeneous set // fail at runtime due to heterogeneous set  27.   String item = (String)listIterator.next();  27.   String item = (String)listIterator.next();  28. }  28. }  29.  29.

66

Can generics help this problemCan generics help this problem

With generics, you achieve With generics, you achieve polymorphic behavior similar to the polymorphic behavior similar to the previous code, but with strong static previous code, but with strong static type-checking; the compiler knows type-checking; the compiler knows that the two lists are different that the two lists are different because they contain different because they contain different elements, and these lists are elements, and these lists are guaranteed to contain only a guaranteed to contain only a homogeneous set of elements. homogeneous set of elements.

77

Previous Example with GenericsPrevious Example with Generics As you can see from comments in the code, all the errors are caught at compile As you can see from comments in the code, all the errors are caught at compile

time. Don't worry about the syntax for now -- we'll cover that shortly. time. Don't worry about the syntax for now -- we'll cover that shortly. In comparing the two examples, you should notice that additional type information In comparing the two examples, you should notice that additional type information

is included in the generics code, which directs the compiler as to what type each is included in the generics code, which directs the compiler as to what type each container should contain. container should contain.

1.1.  2.  import java.util.LinkedList;  2.  import java.util.LinkedList;  3.  import java.util.Collections;  3.  import java.util.Collections;  4.  import java.util.Iterator;  4.  import java.util.Iterator;  5.   5.   6.  public class genericsExample2{  6.  public class genericsExample2{  7.   7.   8.  static public void main(String[] args) {  8.  static public void main(String[] args) {  9.        9.      LinkedList<String> LinkedList<String>  stringList  = new stringList  = new LinkedList<String>();LinkedList<String>();  10.      10.    LinkedList<Integer>LinkedList<Integer> integerList = new integerList = new LinkedList<Integer>();LinkedList<Integer>();  11.   11.   12.    integerList.add(new Integer(1));  12.    integerList.add(new Integer(1));  13.    integerList.add(new Integer(2));  13.    integerList.add(new Integer(2));  14.   14.   15.    stringList.add(new String("I am a String"));  15.    stringList.add(new String("I am a String"));  16.    stringList.add(new Integer(1));   16.    stringList.add(new Integer(1)); // causes a compilation error// causes a compilation error  17.   17.   18.    18.  

88

    /* genericsExample2.java:16: cannot resolve symbol/* genericsExample2.java:16: cannot resolve symbol  19.    ** symbol : method add (java.lang.Integer)  19.    ** symbol : method add (java.lang.Integer)  20.    */  20.    */  21.   21.   22.      22.    Iterator<Integer>Iterator<Integer> listIterator = integerList.iterator(); listIterator = integerList.iterator();  23.    String item;  23.    String item;  24.    while(listIterator.hasNext()) {  24.    while(listIterator.hasNext()) {  25.       item = listIterator.next();   25.       item = listIterator.next(); // causes a compilation error// causes a compilation error  26.         26.         27.       /* genericsExample2.java:25: incompatible types  27.       /* genericsExample2.java:25: incompatible types  28.       ** found : java.lang.Integer  28.       ** found : java.lang.Integer  29.       ** required: java.lang.String  29.       ** required: java.lang.String  30.       */  30.       */  31.    }  31.    }  32.  32.  33.    listIterator = stringList.iterator();   33.    listIterator = stringList.iterator(); // causes a compilation error// causes a compilation error  34.   34.   35.    /* genericsExample2.java:33: incompatible types  35.    /* genericsExample2.java:33: incompatible types  36.    ** found : java.util.Iterator<java.lang.String>  36.    ** found : java.util.Iterator<java.lang.String>  37.    ** required: java.util.Iterator<java.lang.Integer>  37.    ** required: java.util.Iterator<java.lang.Integer>  38.    */  38.    */

  39.    // the iterator is guaranteed to be homogeneous  39.    // the iterator is guaranteed to be homogeneous  40.    while (listIterator.hasNext()) {  40.    while (listIterator.hasNext()) {  41.      item = listIterator.next();  41.      item = listIterator.next();  42.  42.  43.      /* genericsEx2.java:41: incompatible types  43.      /* genericsEx2.java:41: incompatible types  44.      ** found : java.lang.Integer  44.      ** found : java.lang.Integer  45.      ** required: java.lang.String  45.      ** required: java.lang.String  46.      */  46.      */  47.    }  47.    }  48. } // main  48. } // main  49. } // class genericsExample2   49. } // class genericsExample2

99

public class OldBox {Object data;public OldBox(Object data) {

this.data = data;}public Object getData() {

return data;}

}

OldBox intBox = new OldBox(42);int x = (Integer) intBox.getData();

OldBox strBox = new OldBox(“Hi”);String s = (String) strBox.getData();

int y = (Integer) strBox.getData();intBox = strBox;

ClassCastException! Compiles but fails at runtime

ANOTHER Example of Problem without ANOTHER Example of Problem without Generics: Cast Exceptions at RuntimeGenerics: Cast Exceptions at Runtime

1010

public class IntBox { Integer data; public IntBox(Integer data) { this.data = data; } public Integer getData() { return data; }}

public class StrBox { String data; public StrBox(String data) { this.data = data; } public String getData() { return data; }}

IntBox intBox = new IntBox(42);int x = intBox.getData();

StrBox strBox = new StrBox(“Hi”);String s = strBox.getData();

int y = (Integer) strBox.getData();intBox = strBox;

Errors caught by compiler

public class FooBox { Foo data; public FooBox(Foo data) { this.data = data; } public Foo getData() { return data; }}

Infinite many classes possible

Without Generics - NOT A GOOD Without Generics - NOT A GOOD SOLUTIONSOLUTION

1111

Java Generics: Key IdeaJava Generics: Key Idea

Parameterize type definitionsParameterize type definitions• Parameterized classes and methodsParameterized classes and methods

Provide type safetyProvide type safety• Compiler performs type checkingCompiler performs type checking• Prevent runtime cast errorsPrevent runtime cast errors

1212

Generics: Parameterized ClassesGenerics: Parameterized Classes

public class OldBox { Object data; public OldBox(Object data) { this.data = data; } public Object getData() { return data; }}

• We want the box to hold a “specific” class – abstractly represented• Object does not work as we have seen earlier• Solution – parameterize the class definition

public class Box<E> { E data; public Box(E data) { this.data = data; } public E getData() { return data; }}

• E refers to a particular type• The constructor takes an object of type E, not any object• To use this class, E must be replaced with a specific class

USING Generics

1313

How to Use Parameterized ClassesHow to Use Parameterized Classes

public class Box<E> { E data; public Box(E data) { this.data = data; } public E getData() { return data; }}

Box<Integer> intBox = new Box<Integer>(42);int x = intBox.getData();//no cast needed

Box<String> strBox =new Box<String>(“Hi”);String s = strBox.getData();//no cast needed

Following lines will not compile anymore:

String s = (String) intBox.getData();int y = (Integer) strBox.getData();intBox = strBox;

Runtime errors now converted tocompile time errors

1414

When to Use Parameterized When to Use Parameterized ClassesClasses

Particularly useful for “container” Particularly useful for “container” classesclasses• Containers hold but do not process dataContainers hold but do not process data

All All collections framework classescollections framework classes in Java 5.0 and on defined using in Java 5.0 and on defined using genericsgenerics• See the Java API documentationSee the Java API documentation

1515

Collections now use Generic (see Collections now use Generic (see java.util)java.util) Generic interfaceGeneric interface

Generic class implementing Collection interfaceGeneric class implementing Collection interfaceclass LinkedList<A> implements Collection<A> {class LinkedList<A> implements Collection<A> {

protected class Node {protected class Node {

A elt;A elt;

Node next = null;Node next = null;

Node (A elt) { this.elt = elt; }Node (A elt) { this.elt = elt; }

}}

......

}}

interface Iterator<E> { E next(); boolean hasNext();}

interface Collection<A> { public void add (A x); public Iterator<A> iterator ();}

1616

More Collections Code from java.utilMore Collections Code from java.util public interface List<E> {public interface List<E> {

void add(E x); void add(E x); Iterator <E> iterator();Iterator <E> iterator();}}

public interface Iterator<E> {public interface Iterator<E> { E next();E next(); boolean hasNext();boolean hasNext();}}LinkedList is in java.util and implements List interface as a LinkedList is in java.util and implements List interface as a

Generic Class.Generic Class.

HOW TO USE THIS CODEList<Integer> myIntList = new LinkedList<Integer>();

myIntList.add(new Integer(0));Integer x = myIntList.iterator().next();

1717

Parameterized Classes: Syntax Parameterized Classes: Syntax NoteNote

A class can have multiple parameters, e.g:

public class Stuff<A,B,C> { … }

Subclassing parameterized classes allowed, e.g:/* Extending a particular type */class IntBox extends Box<Integer> { … }Or/* Extending a parameterized type */class SpecialBox<E> extends Box<E> { … }

SpecialBox<String> is a subclass of Box<String>./* Following assignment is legal */Box<String> sb = new SpecialBox<String>(“Hi”);

1818

Parameterized Classes in MethodsParameterized Classes in MethodsA parameterized class is a type just like any other class.It can be used in method input types and return types, e.g:Box<String> aMethod(int i, Box<Integer> b) { … }If a class is parameterized, that type parameter can be used for any type declaration in that class, e.g:public class Box<E> { E data; public Box(E data) { this.data = data; } public E getData() { return data; } public void copyFrom(Box<E> b) { this.data = b.getData(); }}//We have added an infinite number of types of Boxes //by writing a single class definition

1919

So Far…So Far…

Type safety violationsType safety violations• Using castsUsing casts

Parameterized classes solve this problemParameterized classes solve this problem Provide type safetyProvide type safety

• Enforced by the compilerEnforced by the compiler Particularly useful for container classesParticularly useful for container classes A parameterized class is another A parameterized class is another typetype Next – bounded parameterized classesNext – bounded parameterized classes

2020

Bounded Parameterized TypesBounded Parameterized TypesSometimes we want restricted parameterization of classes.We want a box, called MathBox that holds only Number objects.We can’t use Box<E> because E could be anything.We want E to be a subclass of Number.

public class MathBox<E extends Number> extends Box<Number> { public MathBox(E data) { super(data); } public double sqrt() { return Math.sqrt(getData().doubleValue()); }}

2121

Bounded Parameterized Types Bounded Parameterized Types (Contd.)(Contd.)

public class MathBox<E extends Number> extends Box<Number> { public MathBox(E data) { super(data); } public double sqrt() { return Math.sqrt(getData().doubleValue()); }}The <E extends Number> syntax means that the type parameter of MathBox must be a subclass of the Number class.We say that the type parameter is bounded.

new MathBox<Integer>(5);//Legalnew MathBox<Double>(32.1);//Legalnew MathBox<String>(“No good!”);//Illegal

2222

Bounded Parameterized Types Bounded Parameterized Types (Contd.)(Contd.)

Inside a parameterized class, the type parameter serves as a valid type.So the following is valid.

public class OuterClass<T> { private class InnerClass<E extends T> { … } …}Syntax note: The <A extends B> syntax is valid even if B is an interface.

2323

Bounded Parameterized Types Bounded Parameterized Types (Contd.)(Contd.)

Java allows multiple inheritance in the form of implementing multiple interfaces. So multiple bounds may be necessary to specify a type parameter. The following syntax is used then:

<T extends A & B & C & …>For instance:

interface A {…}interface B {…}class MultiBounds<T extends A & B> {…}

2424

Parameterized MethodsParameterized Methods

public class Bar<T> {//Bar is parameterized public T aMethod(T x) { return x; } public static void main(String[] args) { Bar<Integer> bar = new Bar<Integer>(); int k = bar.aMethod(5); String s = bar.aMethod("abc"); //Compilation error here }}

Once Bar<T> object is fixed, we are locked to a specific T.

2525

Use of Parameterized MethodsUse of Parameterized Methods

Adding type safety to methods that Adding type safety to methods that operate on different typesoperate on different types• Return type dependent on input typeReturn type dependent on input type

2626

Upper Bounded WildcardsUpper Bounded Wildcards in Parameterized Types in Parameterized Types

The following is a PROBLME:Box<Number> numBox = new Box<Integer>(31);

Compiler comes back with an “Incompatible Type” error message.This is because numBox can hold only a Number object and nothing else, not even an object of type Integer which is a subclass of Number.

The type of numBox we desire is “a Box of any type which extends Number”.

Box<? extends Number> numBox = new Box<Integer>(31);

SOLUTION

2727

Upper Bounded Wildcards in Parameterized Types Upper Bounded Wildcards in Parameterized Types (Contd.)(Contd.)

public class Box<E> { public void copyFrom(Box<E> b) { this.data = b.getData(); }}//We have seen this earlier//We can rewrite copyFrom() so that it can take a box //that contains data that is a subclass of E and //store it to a Box<E> object

public class Box<E> { public void copyFrom(Box<? extends E> b) { this.data = b.getData();//b.getData() is a

//subclass of this.data }}

<? extends E> is called “upper bounded wildcard” because it defines a type that is bounded by the superclass E.

2828

Lower Bounded Wildcards in Parameterized TypesLower Bounded Wildcards in Parameterized Types

Suppose we want to write copyTo() that copies data in the opposite direction of copyFrom().copyTo() copies data from the host object to the given object.

This can be done as:public void copyTo(Box<E> b) { b.data = this.getData();}

Above code is fine as long as b and the host are boxes of exactly same type.But b could be a box of an object that is a superclass of E.This can be expressed as:public void copyTo(Box<? super E> b) { b.data = this.getData(); //b.data() is a superclass of this.data()}

<? super E> is called a “lower bounded wildcard” because it defines a type that is bounded by the subclass E.

2929

Unbounded WildcardsUnbounded Wildcards

Use unbounded wildcards when any type parameter works.<?> is used to specify unbounded wildcards.

The following are legal statements.Box<?> b1 = new Box<Integer>(31);Box<?> b2 = new Box<String>(“Hi”);b1 = b2;

Wildcard capture:The compiler can figure out exactly what type b1 is above from the right hand side of the assignments.

This “capturing” of type information means:1. The type on the left hand doesn’t need to be specified.2. The compiler can do additional type checks because it knows

the type of b1.

3030

ConclusionConclusion

Java genericsJava generics• Parameterized classes and methodsParameterized classes and methods• Type safetyType safety• Syntax and semantics through examplesSyntax and semantics through examples


Recommended