Java Generics

advertisement
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/
Download