Author: saqibkhan

  • No Exception

    A generic class is not allowed to extend the Throwable class directly or indirectly.

    //The generic class Box<T> may not subclass java.lang.Throwable
    class Box<T> extends Exception {}
    
    //The generic class Box<T> may not subclass java.lang.Throwable
    class Box1<T> extends Throwable {}

    A method is not allowed to catch an instance of a type parameter.

    public static <T extends Exception, J> 
       void execute(List<J> jobs) {
    
      try {
         for (J job : jobs) {}
         // compile-time error
         //Cannot use the type parameter T in a catch block
      } catch (T e) { 
         // ...
    } }

    Type parameters are allowed in a throws clause.

    class Box<T extends Exception>  {
       private int t;
    
       public void add(int t) throws T {
    
      this.t = t;
    } public int get() {
      return t;
    } }
  • No Array

    Arrays of parameterized types are not allowed.

    //Cannot create a generic array of Box<Integer>
    Box<Integer>[] arrayOfLists = new Box<Integer>[2]; 

    Because compiler uses type erasure, the type parameter is replaced with Object and user can add any type of object to the array. And at runtime, code will not able to throw ArrayStoreException.

    // compiler error, but if it is allowed
    Object[] stringBoxes = new Box<String>[];
      
    // OK
    stringBoxes[0] = new Box<String>();  
    
    // An ArrayStoreException should be thrown,
    //but the runtime can't detect it.
    stringBoxes[1] = new Box<Integer>();  
  • No instanceOf

    Because compiler uses type erasure, the runtime does not keep track of type parameters, so at runtime difference between Box<Integer> and Box<String> cannot be verified using instanceOf operator.

    Box<Integer> integerBox = new Box<Integer>();
    
    //Compiler Error:
    //Cannot perform instanceof check against 
    //parameterized type Box<Integer>. 
    //Use the form Box<?> instead since further 
    //generic type information will be erased at runtime
    if(integerBox instanceof Box<Integer>) { }
  • No Cast

    Casting to a parameterized type is not allowed unless it is parameterized by unbounded wildcards.

    Box<Integer> integerBox = new Box<Integer>();
    Box<Number> numberBox = new Box<Number>();
    //Compiler Error: Cannot cast from Box<Number> to Box<Integer>
    integerBox = (Box<Integer>)numberBox;

    To achive the same, unbounded wildcards can be used.

    private static void add(Box<?> box) {
       Box<Integer> integerBox = (Box<Integer>)box;
    }
  • No Static field

    Using generics, type parameters are not allowed to be static. As static variable is shared among object so compiler can not determine which type to used. Consider the following example if static type parameters were allowed.

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box&lt;Integer&gt; integerBox = new Box&lt;Integer&gt;();
    Box<String> stringBox = new Box<String>();
      integerBox.add(new Integer(10));
      printBox(integerBox);
    } private static void printBox(Box box) {
      System.out.println("Value: " + box.get());
    } } class Box<T> { //compiler error private static T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    As stringBox and integerBox both have a stared static type variable, its type can not be determined. Hence static type parameters are not allowed.

  • No Instance

    A type parameter cannot be used to instantiate its object inside a method.

    public static <T> void add(Box<T> box) {
       //compiler error
       //Cannot instantiate the type T
       //T item = new T();  
       //box.add(item);
    }

    To achieve such functionality, use reflection.

    public static <T> void add(Box<T> box, Class<T> clazz) 
       throws InstantiationException, IllegalAccessException{
       T item = clazz.newInstance();   // OK
       box.add(item);
       System.out.println("Item added.");
    }

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) 
    
      throws InstantiationException, IllegalAccessException {
      Box&lt;String&gt; stringBox = new Box&lt;String&gt;();
      add(stringBox, String.class);
    } public static <T> void add(Box<T> box) {
      //compiler error
      //Cannot instantiate the type T
      //T item = new T();  
      //box.add(item);
    } public static <T> void add(Box<T> box, Class<T> clazz)
      throws InstantiationException, IllegalAccessException{
      T item = clazz.newInstance();   // OK
      box.add(item);
      System.out.println("Item added.");
    } } class Box<T> { private T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    This will produce the following result −

    Item added.
    
  • No Primitive Types

    Using generics, primitive types can not be passed as type parameters. In the example given below, if we pass int primitive type to box class, then compiler will complain. To mitigate the same, we need to pass the Integer object instead of int primitive type.

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box&lt;Integer&gt; integerBox = new Box&lt;Integer&gt;();
      //compiler errror
      //ReferenceType
      //- Syntax error, insert "Dimensions" to complete
      ReferenceType
      //Box&lt;int&gt; stringBox = new Box&lt;int&gt;();
      integerBox.add(new Integer(10));
      printBox(integerBox);
    } private static void printBox(Box box) {
      System.out.println("Value: " + box.get());
    } } class Box<T> { private T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    This will produce the following result −

    Output

    Value: 10
    
  • Generic Methods Erasure

    Java Compiler replaces type parameters in generic type with Object if unbounded type parameters are used, and with type if bound parameters are used as method parameters.

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box&lt;Integer&gt; integerBox = new Box&lt;Integer&gt;();
      Box&lt;String&gt; stringBox = new Box&lt;String&gt;();
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      
      printBox(integerBox);
      printBox1(stringBox);
    } private static <T extends Box> void printBox(T box) {
      System.out.println("Integer Value :" + box.get());
    } private static <T> void printBox1(T box) {
      System.out.println("String Value :" + ((Box)box).get());
    } } class Box<T> { private T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    In this case, java compiler will replace T with Object class and after type erasure,compiler will generate bytecode for the following code.

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box integerBox = new Box();
      Box stringBox = new Box();
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      
      printBox(integerBox);
      printBox1(stringBox);
    } //Bounded Types Erasure private static void printBox(Box box) {
      System.out.println("Integer Value :" + box.get());
    } //Unbounded Types Erasure private static void printBox1(Object box) {
      System.out.println("String Value :" + ((Box)box).get());
    } } class Box { private Object t; public void add(Object t) {
      this.t = t;
    } public Object get() {
      return t;
    } }

    In both case, result is same −

    Output

    Integer Value :10
    String Value :Hello World
    
  • Unbounded Types Erasure

    Java Compiler replaces type parameters in generic type with Object if unbounded type parameters are used.

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box&lt;Integer&gt; integerBox = new Box&lt;Integer&gt;();
      Box&lt;String&gt; stringBox = new Box&lt;String&gt;();
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
    } } class Box<T> { private T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    In this case, java compiler will replace T with Object class and after type erasure,compiler will generate bytecode for the following code.

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box integerBox = new Box();
      Box stringBox = new Box();
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
    } } class Box { private Object t; public void add(Object t) {
      this.t = t;
    } public Object get() {
      return t;
    } }

    In both case, result is same −

    Output

    Integer Value :10
    String Value :Hello World
    
  • Bound Types Erasure

    Java Compiler replaces type parameters in generic type with their bound if bounded type parameters are used.

    Example

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box&lt;Integer&gt; integerBox = new Box&lt;Integer&gt;();
      Box&lt;Double&gt; doubleBox = new Box&lt;Double&gt;();
      integerBox.add(new Integer(10));
      doubleBox.add(new Double(10.0));
      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("Double Value :%s\n", doubleBox.get());
    } } class Box<T extends Number> { private T t; public void add(T t) {
      this.t = t;
    } public T get() {
      return t;
    } }

    In this case, java compiler will replace T with Number class and after type erasure,compiler will generate bytecode for the following code.

    package com.tutorialspoint;
    
    public class GenericsTester {
       public static void main(String[] args) {
    
      Box integerBox = new Box();
      Box doubleBox = new Box();
      integerBox.add(new Integer(10));
      doubleBox.add(new Double(10.0));
      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("Double Value :%s\n", doubleBox.get());
    } } class Box { private Number t; public void add(Number t) {
      this.t = t;
    } public Number get() {
      return t;
    } }

    In both case, result is same −

    Output

    Integer Value :10
    Double Value :10.0