天天看点

java(36):泛型

日期:2017/11/25

     泛型的使用能够解决处理不同类型数据时遇到的困难。泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

     在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

     泛型的好处是在 编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

代码例子1:

package com.code.generic_paradigm;
//ArrayList<String> a  ; ArrayList  b
import java.util.ArrayList;

public class test02 {
  public static void main(String[] args){
    ArrayList<String> a = new ArrayList<String>();  
    ArrayList  b = new ArrayList();  
    Class c1 = a.getClass();  
    Class c2 = b.getClass();  
    System.out.println(c1.getClass().getName());
    System.out.println(c2.getClass().getName());
    System.out.println(c1 == c2); //true  
  }
}      

代码例子2:

package com.code.generic_paradigm;

class FX<T>{
  private T ob;
  public FX(T ob){
    this.ob = ob ;    
  }
  public T getob(){
    return ob;
  }
  public void showetype(){
    System.out.println("T real parttern is :"+ob.getClass().getName());
  }
}

public class test01 {
  public static void main(String [] args){
    FX<Integer> intob = new FX<Integer>(100) ;
    intob.showetype();
    System.out.println("value="+intob.getob());
    System.out.println("------------------");
    
    FX<String> strob = new FX<String>("mmb");
    strob.showetype();
    System.out.println("value="+strob.getob());
  }

}      

输出结果:

T real parttern is :java.lang.Integer
value=100
------------------
T real parttern is :java.lang.String
value=mmb      

泛型的好处:

(1)类型安全。 

通过知道使用泛型定义的变量的类型限制,编译器可以更有效地提高Java程序的类型安全。 

(2)消除强制类型转换。 

消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。所有的强制转换都是自动和隐式的。

(3)提高性能。 

[java] 

​​view plain​​​

 ​​​copy​​

 ​​​​​​​​

  1. new ArrayList();
  2. "CSDN_SEU_Cavin ");
  3. 0);

[java] 

​​view plain​​​

 ​​​copy​​

 ​​​​​​​​

  1. new ArrayList<String>();
  2. "CSDN_SEU_Cavin ");
  3. 0);

对于上面的两段程序,由于泛型所有工作都在编译器中完成,javac编译出来的字节码是一样的(只是更能确保类型安全),那么何谈性能提升呢?是因为在泛型的实现中,编译器将强制类型转换插入生成的字节码中,但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来了可能。

注意事项

(1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

(2)泛型的类型参数可以有多个。

(3)不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。

[java] 

​​view plain​​​

 ​​​copy​​

 ​​​​​​​​

  1. if(ex_num instanceof FX<Number>){
  2. }

(4)不能创建一个确切的泛型类型的数组。

[java] 

​​view plain​​​

 ​​​copy​​

 ​​​​​​​​

  1. new List<String>[10]; // Not really allowed.
  2. Object o = lsa;
  3. Object[] oa = (Object[]) o;
  4. new ArrayList<Integer>();
  5. new Integer(3));
  6. 1] = li; // Unsound, but passes run time store check
  7. 1].get(0); // Run-time error: ClassCastException.

这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList<Integer>而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。

下面采用通配符的方式是被允许的:

[java] 

​​view plain​​​

 ​​​copy​​

 ​​​​​​​​

  1. new List<?>[10]; // OK, array of unbounded wildcard type.
  2. Object o = lsa;
  3. Object[] oa = (Object[]) o;
  4. new ArrayList<Integer>();
  5. new Integer(3));
  6. 1] = li; // Correct.
  7. 1].get(0); // OK