Generics in Java

The Java Generics programming is introduced in J2SE 5 to deal with type-safe objects. It makes the code stable by detecting the bugs at compile time.

一、Advantages of Generics:
1. Code Reuse

We can write a method/class/interface once and use for any type we want.

2. Type Safety

Generics make errors to appear compile time than at run time (It’s always better to know problems in your code at compile time rather than making your code fail at run time). Suppose you want to create an ArrayList that store name of students and if by mistake programmer adds an integer object instead of string, compiler allows it. But, when we retrieve this data from ArrayList, it causes problems at runtime.

List list = new ArrayList();    
list.add(10);  
list.add("10");  
With Generics, it is required to specify the type of object we need to store.  
List<Integer> list = new ArrayList<Integer>();    
list.add(10);  
list.add("10");// compile-time error  
3. Individual Type Casting is not needed

If we do not use generics, then, in the above example every-time we retrieve data from ArrayList, we have to typecast it. Typecasting at every retrieval operation is a big headache. If we already know that our list only holds string data then we need not to typecast it every time.

List list = new ArrayList();    
list.add("hello");    
String s = (String) list.get(0);//typecasting    
After Generics, we don't need to typecast the object.  
List<String> list = new ArrayList<String>();    
list.add("hello");    
String s = list.get(0);    
4. Compile-Time Checking

It is checked at compile time so problem will not occur at runtime. The good programming strategy says it is far better to handle the problem at compile time than runtime.

List<String> list = new ArrayList<String>();    
list.add("hello");    
list.add(32);//Compile Time Error  
二、Type Parameters

The type parameters naming conventions are important to learn generics thoroughly. The common type parameters are as follows:

T - Type
E - Element
K - Key
N - Number
V - Value

三、Generic class

A class that can refer to any type is known as a generic class. Here, we are using the T type parameter to create the generic class of specific type.

Let’s see a simple example to create and use the generic class.
Creating a generic class:

class MyGen<T>{  
T obj;  
void add(T obj){this.obj=obj;}  
T get(){return obj;}  
}  

The T type indicates that it can refer to any type (like String, Integer, and Employee). The type you specify for the class will be used to store and retrieve the data.

Using generic class:

class TestGenerics3{  
public static void main(String args[]){  
MyGen<Integer> m=new MyGen<Integer>();  
m.add(2);  
//m.add("vivek");//Compile time error  
System.out.println(m.get());  
}}  
四、Generic Method

Like the generic class, we can create a generic method that can accept any type of arguments. Here, the scope of arguments is limited to the method where it is declared. It allows static as well as non-static methods.

public class TestGenerics4{  
  
   public static < E > void printArray(E[] elements) {  
        for ( E element : elements){          
            System.out.println(element );  
         }  
         System.out.println();  
    }  
    public static void main( String args[] ) {  
        Integer[] intArray = { 10, 20, 30, 40, 50 };  
        Character[] charArray = { 'J', 'A', 'V', 'A', 'T','P','O','I','N','T' };  
  
        System.out.println( "Printing Integer Array" );  
        printArray( intArray  );   
  
       System.out.println( "Printing Character Array" );  
        printArray( charArray );   
    }   
}  

Output:

Printing Integer Array
10
20
30
40
50
Printing Character Array
J
A
V
A
T
P
O
I
N
T
五、Wildcard in Java Generics

The ? (question mark) symbol represents the wildcard element. It means any type. If we write <? extends Number>, it means any child class of Number, e.g., Integer, Float, and double. Now we can call the method of Number class through any child class object.

We can use a wildcard as a type of a parameter, field, return type, or local variable. However, it is not allowed to use a wildcard as a type argument for a generic method invocation, a generic class instance creation, or a supertype.

import java.util.*;  
abstract class Shape{  
abstract void draw();  
}  
class Rectangle extends Shape{  
void draw(){System.out.println("drawing rectangle");}  
}  
class Circle extends Shape{  
void draw(){System.out.println("drawing circle");}  
}  
class GenericTest{  
//creating a method that accepts only child class of Shape  
public static void drawShapes(List<? extends Shape> lists){  
for(Shape s:lists){  
s.draw();//calling method of Shape class by child class instance  
}  
}  
public static void main(String args[]){  
List<Rectangle> list1=new ArrayList<Rectangle>();  
list1.add(new Rectangle());  
  
List<Circle> list2=new ArrayList<Circle>();  
list2.add(new Circle());  
list2.add(new Circle());  
  
drawShapes(list1);  
drawShapes(list2);  
}}  

Output:

drawing rectangle
drawing circle
drawing circle
六、Upper Bounded Wildcards

The purpose of upper bounded wildcards is to decrease the restrictions on a variable. It restricts the unknown type to be a specific type or a subtype of that type. It is used by declaring wildcard character ("?") followed by the extends (in case of, class) or implements (in case of, interface) keyword, followed by its upper bound.
Syntax:

List<? extends Number>

Here,

? is a wildcard character.

extends, is a keyword.

Number, is a class present in java.lang package

Suppose, we want to write the method for the list of Number and its subtypes (like Integer, Double). Using List<? extends Number> is suitable for a list of type Number or any of its subclasses whereas List works with the list of type Number only. So, List<? extends Number> is less restrictive than List.
Example of Upper Bound Wildcard:

import java.util.ArrayList;  
  
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));  
          
          
    }  
      
}  

Output:

displaying the sum= 30.0
displaying the sum= 70.0
七、Unbounded Wildcards

The unbounded wildcard type represents the list of an unknown type such as List<?>. This approach can be useful in the following scenarios: -

When the given method is implemented by using the functionality provided in the Object class.
When the generic class contains the methods that don’t depend on the type parameter.

Example of Unbounded Wildcards

import java.util.Arrays;  
import java.util.List;  
  
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);  
    }  
  
}  

Output:

displaying the Integer values
1
2
3
displaying the String values
One
Two
Three
八、Lower Bounded Wildcards

The purpose of lower bounded wildcards is to restrict the unknown type to be a specific type or a supertype of that type. It is used by declaring wildcard character ("?") followed by the super keyword, followed by its lower bound.
Syntax:

List<? super Integer>  

Here,

? is a wildcard character.

super, is a keyword.

Integer, is a wrapper class.

Suppose, we want to write the method for the list of Integer and its supertype (like Number, Object). Using List<? super Integer> is suitable for a list of type Integer or any of its superclasses whereas List works with the list of type Integer only. So, List<? super Integer> is less restrictive than List.

Example of Lower Bound Wildcard:

import java.util.Arrays;  
import java.util.List;  
  
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);  
}  
  
}  

Output:

displaying the Integer values
1
2
3
displaying the Number values
1.0
2.0
3.0
九、What is not allowed to do with Generics?
1.You can’t have static field of type

You can not define a static generic parameterized member in your class. Any attempt to do so will generate compile time error: Cannot make a static reference to the non-static type T.

public class GenericsExample<T>
{
   private static T member; //This is not allowed
}
2. You can not create an instance of T

Any attempt to create an instance of T will fail with error: Cannot instantiate the type T.

public class GenericsExample<T>
{
   public GenericsExample(){
      new T();
   }
}
3.Generics are not compatible with primitives in declarations

Yes, it’s true. You can’t declare generic expression like List or Map<String, double>. Definitely you can use the wrapper classes in place of primitives and then use primitives when passing the actual values. These value primitives are accepted by using auto-boxing to convert primitives to respective wrapper classes.

final List<int> ids = new ArrayList<>();    //Not allowed
 
final List<Integer> ids = new ArrayList<>(); //Allowed
4.You can’t create Generic exception class

Sometimes, programmer might be in need of passing an instance of generic type along with exception being thrown. This is not possible to do in Java.

// causes compiler error
public class GenericException<T> extends Exception {}

When you try to create such an exception, you will end up with message like this: The generic class GenericException may not subclass java.lang.Throwable.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值