Generics in Java

Generics in Java

Table of Contents

Generics deal with type-safe objects making the code stable by detecting the bug at compile time.

Before Generics was introduced, we can store any type of data in the collection. Now, in Generics, we can store only a specific type of object.

Advantages of Generics:

1] Type-Safety: We can now store only a specific type of object. We cannot store other objects in the collection.

2] We do not need to typecast the object, so Typecasting is not required.

3] It can detect the errors at compile time itself, and hence the problem does not occur at run time.

4] Type Erasure: Any extra information added using Generics into source code will get removed as soon as its byte code is generated.

Type Parameters:

The standard type parameters are:

T – Type

K – Key

E – Element

V – Value

N – Number

Generic Class:

When more than one type of parameter is declared in a class, it is said to be as Generic Class.

class DemoClass 

{

   private Object t;

   public void set(Object t) 

{ 

this.t = t; 

}

   public Object get() 

{

 return t; 

}

}

Generic Method:

Generic Method is the same as Generic Class, where more than one type of parameter can be declared. The only difference between the Generic method and Generic class is that the scope of a type parameter resides within its method.

public static <T> int countAllOccurrences(T[] list, T item) {

   int count = 0;

   if (item == null) {

      for ( T listItem : list )

         if (listItem == null)

            count++;

   }

   else {

      for ( T listItem : list )

         if (item.equals(listItem))

            count++;

   }

   return count;

}   

Generics With Wildcards:

The ? (question mark) denotes the wildcard. It can be used as a type of a parameter, a local variable, field or return type. Examples of wildcard parameterized types includes Collection<?<, List<? extends Number<, Comparator<? super String> and Pair<String,?>. Wildcards can be either bounded or unbounded.

abstract class Shaper{  

abstract void draw();  

}  

class Triangle extends Shaper{  

void draw(){System.out.println("drawing Triangle");}  

}  

class Square extends Shaper{  

void draw(){System.out.println("drawing Square");}  

}  

class GenericTest{  

public static void drawShapers(List<? extends Shaper> lists){  

for(Shaper s:lists){  

s.draw();//calling method of Shaper class by child class instance  

}  

}  

public static void main(String args[]){  

List<Triangle> list1=new ArrayList<Triangle>();  

list1.add(new Triangle());  

  

List<Square> list2=new ArrayList<Square>();  

list2.add(new Square());  

list2.add(new Square());  

  

drawShapers(list1);  

drawShapers(list2);  

}}  

Bounded Wildcards:

Bounded wildcards have some restrictions on type parameters. This restriction can be enforced using super and extends keyword.

1] Upper Bounded Wildcards: This is used to decrease the restriction on a variable. It is declared by using wildcard character following by extends or implements and then following by its upper bound.

public class UpperBoundWildcard {  

    private static Double add(ArrayList<? extends Number> num) {  

        double sum=0.0;   

        for(Number n:num)  

        {  

            sum = sum+n.doubleValue();  

        } 

        return sum;  

    }  

    public static void main(String[] args) {    

        ArrayList<Integer> l1=new ArrayList<Integer>();  

        l1.add(10);  

        l1.add(20);  

        System.out.println("displaying the sum= "+add(l1));  

        ArrayList<Double> l2=new ArrayList<Double>();  

        l2.add(30.0);  

        l2.add(40.0);  

        System.out.println("displaying the sum= "+add(l2));     

    } 

} 

2] Lower Bounded Wildcards: This is used to decrease the restriction on the unknown type to be a specific type or a supertype. It is declared by using wildcard character following by super keyword and then following by it lower bound.

public class LowerBoundWildcard {  

    public static void addNumbers(List<? super Integer> list) {  

        for(Object n:list)  

        {  

              System.out.println(n);  

        }  

    }  

public static void main(String[] args) {  

    List<Integer> l1=Arrays.asList(1,2,3);  

      System.out.println("displaying the Integer values");  

    addNumbers(l1);  

    List<Number> l2=Arrays.asList(1.0,2.0,3.0);  

      System.out.println("displaying the Number values");  

    addNumbers(l2);  

}  

}  

Unbounded Wildcards:

It represents the list of an unknown type say for eg. List<?>. Unbounded wildcards are useful in two cases:

  1. When the method is implemented in the Object Class.
  2. When Generic Class contains those methods which do not depend on the type parameter.
public class UnboundedWildcard {  

    public static void display(List<?> list)  

    {  

        for(Object o:list)  

        {  

            System.out.println(o);  

        }      

    }  

    public static void main(String[] args) {  

    List<Integer> l1=Arrays.asList(1,2,3);  

    System.out.println("displaying the Integer values");  

    display(l1);  

    List<String> l2=Arrays.asList("One","Two","Three");  

      System.out.println("displaying the String values");  

        display(l2);  

    }  

}  

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share this article
Subscribe
By pressing the Subscribe button, you confirm that you have read our Privacy Policy.
Need a Free Demo Class?
Join H2K Infosys IT Online Training
Enroll Free demo class