Java Generics • It is nice if we could write a single sort method that could sort array of any type of elements: – Integer array, – String array, • Solution: Generics! • Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Advantages of Generics 1. Stronger type checks at compile time: – A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. 2. Elimination of casts. Using no generics requires casting: List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); Using generics, require nocasting: List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); 3. Enabling programmers to implement generic algorithms. – By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read. – E.g. a single sort method that sort an array of any type element with ordering Generic Types • A generic type is a generic class or interface that is parameterized over types. • Let’s begin by examining a non-generic Box class that operates on objects of any type. • You are free to pass in whatever object you want to methods. • There is no way to verify, at compile time, how the class is used. – One part of the code may place an Integer in the box – Another part of the code may mistakenly pass in a String, resulting in a runtime error. A Generic Version of the Box Class • A generic class is defined with the following format: class name<T1, T2, ..., Tn> { /* ... */ } type parameters (type variables) T1, T2, ..., and Tn • With this change, the Box class becomes: – all occurrences of Object are replaced by T • A type variable can be any non-primitive type you specify: – any class type, – any interface type, – any array type, or even – another type variable. • This same technique can be applied to create generic interfaces. Type Parameter Naming Conventions • By convention, type parameter names are single, uppercase letters. • The most commonly used type parameter names are: – – – – – – E - Element (used extensively by Java Collections Framework) K - Key N - Number T - Type V - Value S,U,V etc. - 2nd, 3rd, 4th types Invoking and Instantiating a Generic Type • To reference the generic Box class from within your code, you must perform a generic type invocation – replaces T with some concrete value, such as Integer: Box<Integer> integerBox; – Similar to an ordinary method invocation, but instead of passing an argument to a method, you are passing a type argument —Integer in this case — to the Box class itself. • To instantiate this class, use the new keyword, as usual, but place <Integer> between the class name and the parenthesis: Box<Integer> integerBox = new Box<Integer>(); Programming Question • Write class Box and a tester class GenericsTester. In tester class initialize a Box object of Integer type, set it’s value 3, retrieve and print Box value. Answer Box.java /** * Generic version of the Box class. * @param <T> the type of the value being boxed */ public class Box<T> { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } } public class GenericsTester { public static void main(String args[]) { Box<Integer> integerBox = new Box<Integer>(); integerBox.set(new Integer(3)); Integer n = integerBox.get(); System.out.println(n); } } Multiple Type Parameters • Generic class can have multiple type parameters. • E.g., the generic OrderedPair class, which implements the generic Pair interface: • The following statements create two instantiations of the OrderedPair class: – Due to autoboxing, it is valid to pass a String and an int to the class. • Above statements can be shortened using diamond notation: • To create a generic interface, follow the same conventions as for creating a generic class. Programming Question • Create Pair interface and OrderedPair generic class. Then modify GenericsTester to create two ordered pair objects (as given in example) and print keys and values of both pairs. Answer public interface Pair<K, V> { public K getKey(); public V getValue(); } Pair.java OrderedPair.java public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } GenericsTester.java public class GenericsTester { public static void main(String args[]) { Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world"); System.out.println("p1 key:"+p1.getKey()+" p1 value:"+p1.getValue()); System.out.println("p2 key:"+p2.getKey()+" p2 value:"+p2.getValue()); } } Parameterized Types • You can also substitute a type parameter (i.e., K or V) with a parameterized type (i.e., List<String>). • For example, using the OrderedPair<K, V> example: Raw Types • A raw type is the name of a generic class or interface without any type arguments. • To create a parameterized type of Box<T>: – you supply an actual type argument for the formal type parameter T: Box<Integer> intBox = new Box<>(); • To create a raw type of Box<T>: – Omit actual type argument Box rawBox = new Box(); • Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. • Read more: – http://docs.oracle.com/javase/tutorial/java/generics/rawT ypes.html Generic Methods • • • • Methods that introduce their own type parameters. Similar to declaring a generic type But the type parameter's scope is limited to the method The Util class includes a generic method, compare, which compares two Pair objects: • The complete syntax for invoking this method would be: • Generally, type can be left out and the compiler will infer the type (type inference): Programming Question • Modify the Generics tester to implement a generic method printArray. The method should accept an array of a generic type (E or T) and print all array elements. • In the main method create three arrays: – An Integer array intArray with 5 Integer values – A Double array doubleArray with 5 Double values – A Character array charArray with 5 Characters. – Then call priintArray method for all 3 arrays. Answer public class GenericsTester { public static void main(String args[]) { // Create arrays of Integer, Double and Character Integer[] intArray = { 1, 4, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println( "Array integerArray contains:" ); printArray( intArray ); // pass an Integer array System.out.println( "\nArray doubleArray contains:" ); printArray( doubleArray ); // pass a Double array System.out.println( "\nArray characterArray contains:" ); printArray( charArray ); // pass a Character array } // generic method printArray public static < E > void printArray( E[] inputArray ) { // Display array elements for ( E element : inputArray ){ System.out.printf( "%s ", element ); } System.out.println(); } } Bounded Type Parameters • Sometimes you want to restrict the kinds of types that are allowed to be passed to a type parameter. • E.g., a method that operates on numbers might only want to accept instances of Number or its subclasses. • Solution: use bounded type parameters ! • To declare a bounded type parameter: – list the type parameter's name, followed by the extends keyword, followed by its upper bound. Example public class MaximumTest { // determines the largest of three Comparable objects public static <T extends Comparable<T>> T maximum(T x, T y, T z) { T max = x; // assume x is initially the largest if ( y.compareTo( max ) > 0 ){ max = y; // y is the largest so far} if ( z.compareTo( max ) > 0 ){ max = z; // z is the largest now} return max; // returns the largest object } public static void main( String args[] ) { System.out.printf( "Max of %d, %d and %d is %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "Maxm of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "Max of %s, %s and %s is %s\n","pear", "apple", "orange", maximum( "pear", "apple", "orange" ) ); } } Programming Question • Modify class GenericsTester to implement generics version of selection sort method. Then call this on an Integer and a Double Array. • Non-generic version: public static int[] sort(int[] a) { int N = a.length; for (int i = 0; i < N; i++) { int min = i; for (int j = i+1; j < N; j++) { if ((a[j]<a[min]) { min = j; } int temp = a[i]; a[i]= a[min]; a[min]=temp; } return a; } } Answer public class SelectionSorter { public static <T extends Comparable<T>> T[] sort(T[] a) { int N = a.length; for (int i = 0; i < N; i++) { int min = i; for (int j = i+1; j < N; j++) { if ((a[j].compareTo(a[min]))<0) { min = j; } } T temp = a[i]; a[i]= a[min]; a[min]=temp; } return a; } public static void main(String args[]) { Integer[] intArray = {1,30,20, 10, 3}; intArray = sort(intArray); for(int n: intArray) System.out.print(" "+ n); } } • Read more: – http://docs.oracle.com/javase/tutorial/java/gener ics/