Showing posts with label Generic Revealed. Show all posts
Showing posts with label Generic Revealed. Show all posts

Restrictions on Generics :





Cannot Instantiate Generic Types with Primitive Types:

Consider the following parameterized type:
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
// ...
}



Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error
Pair<Integer, Character> p = new Pair<>(8, 'a');
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));
When creating a Pair object, you cannot subsitute a primitive type for the type parameter K or V:
You can substitute only non-primitive types for the type parameters K and V:
Note that the Java compiler autoboxes 8 to Integer.valueOf(8) and 'a' to Character('a').







Cannot Declare Static Fields Whose Types are Type Parameters

public class MobileDevice<T> {

private static T os;

// ...
}
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();


A class's static field is a class-level variable shared by all non-static objects of the class. Hence, static fields of type parameters are not allowed. Consider the following class:
If static fields of type parameters were allowed, then the following code would be confused:
Because the static field os is shared by phonepager, and pc, what is the actual type of os? It cannot be SmartphonePager, and TabletPC at the same time. You cannot, therefore, create static fields of type parameters.






Cannot Create Arrays of Parameterized Types:

You cannot create arrays of parameterized types. For example, the following code does not compile:
List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error





Cannot Create, Catch, or Throw Objects of Parameterized Types :

A generic class cannot extend the Throwable class directly or indirectly. For example, the following classes will not compile:
// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // compile-time error

// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // compile-time error

A method cannot catch an instance of a type parameter:




public static <T extends Exception, J> void execute(List<J> jobs) {
    try {
        for (J job : jobs)
            // ...
    } catch (T e) {   // compile-time error
        // ...
    }
}


You can, however, use a type parameter in a throws clause:
class Parser<T extends Exception> {
    public void parse(File file) throws T {     // OK
        // ...
    }
}











Wildcards in Generics

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific). The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.



Upper Bounded Wildcards:


You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>List<Double>,and List<Number>; you can achieve this by using an upper bounded wildcard.
To declare an upper-bounded wildcard, use the wildcard character ('?'), followed by the extends keyword, followed by its upper bound. Note that, in this context, extends is used in a  sense to mean either "extends" (as in classes) or "implements" (as in interfaces). To write the method that works on lists of Number and the sub-types of Number, such as IntegerDouble, and Float, you would specify List<? extends Number>. The term List<Number> is more restrictive than List<? extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses.

Consider the following process method:

public static void process(List<? extends Test> list) { /* ... */ }

The upper bounded wildcard, <? extends Test>, where Test is any type, matches Test and any subtype of Test. The process method can access the list elements as type Test:
public static void process(List<? extends Test> list) {
    for (Test var : list) {
        // ...
    }
}




Unbounded Wildcards:

The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach:
  • If you are writing a method that can be implemented using functionality provided in the Object class.
  • When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> do not depend on T.



Consider the following method, printList:


public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}



The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>List<String>,List<Double>, and so on, because they are not subtypes of List<Object>.



 To write a generic printList method, use List<?>:




public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}




It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>.












Benefit of using Generics in Java

 Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods.

Code that uses generics has many benefits over non-generic code:
  • 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. Fixing compile-time errors is easier than fixing run-time errors, which can be difficult to find.
             
  • Elimination of casts.
    The following code snippet without generics requires casting:
    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);
    
    When re-written to use generics, the code does not require casting:
    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0);   // no cast
 
Copyright (c) 2013 Java Discovery.