Java Generics

Download Report

Transcript Java Generics

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);
Try this code in DrJava
interaction pane.
If you add an integer (say
3) will compiler
complain?
Using generics, require no casting:
List<String> list = new ArrayList<String>();
list.add("hello");
Try this code in DrJava
String s = list.get(0);
interaction pane.
If you add an integer (say
3) will compiler
complain?
No compiler error if you add different
data-type elements
Compiler error if you add different
data-type element than one specified
at the time of creating list
(Strong type checking at compile time!)
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
• 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
• Perform a generic type invocation
– replace 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 generic class Box.
• Use following tester class to test.
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);
}
}
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 that implement it.
• 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.
• 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 GenericsTester to implement a generic
method printArray. The method should accept an array
of a generic type (E or T) and print all array elements.
Find code
template
next slide
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
}
//TODO: generic method printArray
}
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;
}
}
Find code
template
next slide
public class SelectionSorter
{
//TODO: generic selection sort method
public static void main(String args[])
{
Integer[] intArray = {1,30,20, 10, 3};
intArray = sort(intArray);
for(int n: intArray)
System.out.print(" "+ n);
}
}
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/