CPSC 331: Data Structures, Algorithms, and their Analysis - - PowerPoint PPT Presentation

cpsc 331 data structures algorithms and their analysis
SMART_READER_LITE
LIVE PREVIEW

CPSC 331: Data Structures, Algorithms, and their Analysis - - PowerPoint PPT Presentation

CPSC 331: Data Structures, Algorithms, and their Analysis Introduction to Java Generics Usman R. Alim Department of Computer Science Generics in Java Often times, we want to perform the same operations on various different types of data.


slide-1
SLIDE 1

CPSC 331: Data Structures, Algorithms, and their Analysis

Introduction to Java Generics Usman R. Alim

Department of Computer Science

slide-2
SLIDE 2

Generics in Java

Often times, we want to perform the same operations on various different types of data. Rather than repeating the code for different types, it would be nice to have the same code work for all types. (e.g. a sort function that works on integers, doubles as well as strings.) Introduced in JDK 5, generics provide us with a way of accomplishing this. You have probably already used them without even realizing it. There are generics methods, classes and interfaces.

slide-3
SLIDE 3

Pair Example: Without Generics

Consider a class that holds a pair of values of any type. Prior to Java 5, we’d do something like:

public class Pair { Object x; Object y; public Pair( Object x, Object y ) { this.x = x; this.y = y; } public Object getX () { return x; } public Object getY () { return y; } // ... }

slide-4
SLIDE 4

Pair Example: Without Generics

We can use this class to hold e.g. a pair of integers, or a pair of doubles.

Pair pair1 = new Pair(new Integer (1), new Integer (2)); Pair pair2 = new Pair(new Double (1.) , new Double (2.));

slide-5
SLIDE 5

Pair Example: Without Generics

We can use this class to hold e.g. a pair of integers, or a pair of doubles.

Pair pair1 = new Pair(new Integer (1), new Integer (2)); Pair pair2 = new Pair(new Double (1.) , new Double (2.));

However, in order to retrieve an object, an explicit cast is needed.

int k = (Integer)pair1.getX (); double d = (Double)pair2.getY ();

slide-6
SLIDE 6

Pair Example: Without Generics

We can use this class to hold e.g. a pair of integers, or a pair of doubles.

Pair pair1 = new Pair(new Integer (1), new Integer (2)); Pair pair2 = new Pair(new Double (1.) , new Double (2.));

However, in order to retrieve an object, an explicit cast is needed.

int k = (Integer)pair1.getX (); double d = (Double)pair2.getY ();

This is inconvenient and also leads to type safety issues. E.g. the following statements don’t signal any compile-time errors but will give runtime errors.

int k = (Integer)pair2.getX (); // error double d = (Double)pair1.getY (); // error

slide-7
SLIDE 7

Pair Example: With Generics

Generic classes allow us to write classes with parametrized types. Our pair example now looks like:

public class Pair <T1 , T2 > { T1 x; // x is of type T1 T2 y; // y is of type T2 public Pair( T1 x, T2 y ) { this.x = x; this.y = y; } public T1 getX () { return x; } public T2 getY () { return y; } // ... }

Here, T1 and T2 are type parameters.

slide-8
SLIDE 8

Pair Example: With Generics

A pair of integers can now be created as follows:

Pair <Integer , Integer > pair1 = new Pair <Integer , Integer > (new Integer (1), new Integer (2));

slide-9
SLIDE 9

Pair Example: With Generics

A pair of integers can now be created as follows:

Pair <Integer , Integer > pair1 = new Pair <Integer , Integer > (new Integer (1), new Integer (2));

Arguments of the second diamond operator (<>) can be omitted, and we can use autoboxing e.g.

Pair <Integer , Integer > pair1 = new Pair <>(1, 2);

slide-10
SLIDE 10

Pair Example: With Generics

A pair of integers can now be created as follows:

Pair <Integer , Integer > pair1 = new Pair <Integer , Integer > (new Integer (1), new Integer (2));

Arguments of the second diamond operator (<>) can be omitted, and we can use autoboxing e.g.

Pair <Integer , Integer > pair1 = new Pair <>(1, 2);

Casts are no longer necessary, incompatible type assignments are checked at compile time, e.g.

Double d1 = pair1.getX (); // not allowed double d2 = pair1.getX (); // ok due to unboxing

slide-11
SLIDE 11

Extending Generic Classes

Generic classes can be extended to non-generic or generic classes.

slide-12
SLIDE 12

Extending Generic Classes

Generic classes can be extended to non-generic or generic classes. Let’s extend the Pair class to a Point class:

public class Point extends Pair <Double , Double > { public Point(Double x, Double y) { super(x,y); } public double getLength2 () { return getX ()* getX () + getY ()* getY (); } }

slide-13
SLIDE 13

Extending Generic Classes

Generic classes can be extended to non-generic or generic classes. Let’s extend the Pair class to a Point class:

public class Point extends Pair <Double , Double > { public Point(Double x, Double y) { super(x,y); } public double getLength2 () { return getX ()* getX () + getY ()* getY (); } }

Point is a non-generic class:

Point p = new Point( new Double (1.) , new Double (2.)); System.out.println( p.getLength2 () );

slide-14
SLIDE 14

Extending Generic Classes

Let’s extend the Pair class to a generic Triple class that has only

  • ne type parameter.

public class Triple <T> extends Pair <T, T> { T z; // add another member public Triple(T x, T y, T z) { super(x,y); this.z = z; } public T getZ () { return z; } }

slide-15
SLIDE 15

Extending Generic Classes

Let’s extend the Pair class to a generic Triple class that has only

  • ne type parameter.

public class Triple <T> extends Pair <T, T> { T z; // add another member public Triple(T x, T y, T z) { super(x,y); this.z = z; } public T getZ () { return z; } }

Triple is a generic class:

Triple <Integer > tr = new Triple <> (new Integer (1), new Integer (2), new Integer (3)); System.out.println( tr.getZ () );

slide-16
SLIDE 16

Generics and Subtyping

If B is a subtype of A and G is a generic type, it is not the case that G<B> is a subtype of G<A>.

slide-17
SLIDE 17

Generics and Subtyping

If B is a subtype of A and G is a generic type, it is not the case that G<B> is a subtype of G<A>. For example, a Triple<Integer> is-a Pair<Integer, Integer>:

Triple <Integer > tr = new Triple <> (new Integer (1), new Integer (2), new Integer (3)); Pair <Integer , Integer > pr = tr; // ok

slide-18
SLIDE 18

Generics and Subtyping

If B is a subtype of A and G is a generic type, it is not the case that G<B> is a subtype of G<A>. For example, a Triple<Integer> is-a Pair<Integer, Integer>:

Triple <Integer > tr = new Triple <> (new Integer (1), new Integer (2), new Integer (3)); Pair <Integer , Integer > pr = tr; // ok

However, a Triple<Integer> is not a Triple<Object> even though an Integer is-an Object:

Triple <Integer > tr = new Triple <> (new Integer (1), new Integer (2), new Integer (3)); Triple <Object > tro = tr; // error!

slide-19
SLIDE 19

Wildcards

The previous example raises an interesting question, is there a generic type that can be used as a supertype? Yes, Java has wildcard types.

slide-20
SLIDE 20

Wildcards

The previous example raises an interesting question, is there a generic type that can be used as a supertype? Yes, Java has wildcard types. The type Triple<?> is a wildcard type that can be used to refer to any kind of Triple. For example the method

void printTriple( Triple <?> tr ) { System.out.println( "" + tr.getX () + ’\n’ + tr.getY () + ’\n’ + tr.getZ () ); }

can be used to print out any kind of triple.

slide-21
SLIDE 21

Wildcards

The previous example raises an interesting question, is there a generic type that can be used as a supertype? Yes, Java has wildcard types. The type Triple<?> is a wildcard type that can be used to refer to any kind of Triple. For example the method

void printTriple( Triple <?> tr ) { System.out.println( "" + tr.getX () + ’\n’ + tr.getY () + ’\n’ + tr.getZ () ); }

can be used to print out any kind of triple. Wildcards can also be used to refer to subtypes or supertypes of parameter types, e.g.

G<? extends A> g1; // anything that is a subtype of A G<? super B> g2; // anything that is a supertype of B

slide-22
SLIDE 22

Generic Methods

Like generic classes, we can declare generic methods that have one

  • r more parametrized types.
slide-23
SLIDE 23

Generic Methods

Like generic classes, we can declare generic methods that have one

  • r more parametrized types.

For example, we can write a generic method to print a Triple as follows:

public static <T> void printTriple( Triple <T> tr ) { System.out.println( "" + tr.getX () + ’\n’ + tr.getY () + ’\n’ + tr.getZ () ); }

slide-24
SLIDE 24

Generic Methods

Like generic classes, we can declare generic methods that have one

  • r more parametrized types.

For example, we can write a generic method to print a Triple as follows:

public static <T> void printTriple( Triple <T> tr ) { System.out.println( "" + tr.getX () + ’\n’ + tr.getY () + ’\n’ + tr.getZ () ); }

When calling a generic method, the type is automatically inferred, e.g.

Triple <Integer > tr = new Triple <> (new Integer (1), new Integer (2), new Integer (3)); printTriple( tr ); // calls the generic method

slide-25
SLIDE 25

Example: Generic Insertion Sort

To sort items, they have to be comparable. This is assured through the java.lang.Comparable<T> interface. We can use a generic method but restrict it to those types that implement the Comparable<T> interface:

public <T extends Comparable <T>> void insertionSort ( T[] data ) { for(int i = 1, j; i < data.length; i++) { T tmp = data[i]; for(j = i; j > 0 && tmp.compareTo(data[j -1]) < 0; j--) data[j] = data[j -1]; data[j] = tmp; } }

slide-26
SLIDE 26

Caveats

Cannot declare static fields whose types are generic:

public class G<T> { private static T var; //not allowed //... }

slide-27
SLIDE 27

Caveats

Cannot declare static fields whose types are generic:

public class G<T> { private static T var; //not allowed //... }

Cannot use primitive types as type parameters:

Triple <int > tr1; // not allowed Triple <Integer > tr2; // ok

slide-28
SLIDE 28

Caveats

Cannot declare static fields whose types are generic:

public class G<T> { private static T var; //not allowed //... }

Cannot use primitive types as type parameters:

Triple <int > tr1; // not allowed Triple <Integer > tr2; // ok

Cannot instantiate generic types in a generic context:

T obj = new T(); // not allowed T[] arr = new T[10]; // not allowed

slide-29
SLIDE 29

Caveats

Cannot declare static fields whose types are generic:

public class G<T> { private static T var; //not allowed //... }

Cannot use primitive types as type parameters:

Triple <int > tr1; // not allowed Triple <Integer > tr2; // ok

Cannot instantiate generic types in a generic context:

T obj = new T(); // not allowed T[] arr = new T[10]; // not allowed

There are more restrictions, please see https://docs.oracle.com/javase/tutorial/java/generics/ for details.