一、泛型的基本概念

  • 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
  • 泛型的作用:
  • 1、类型检查:
  • 2、类型的强转
  • 关于是实现多类型的功能,Object也可以实现,但是Object类型并没有涉及到类型检查。

二、泛型类

  • 泛型类(generic class):就是具有一个或多个类型变量的类。以GenericMath类为例
class GenericMath<T >{
public int sumFunc(T[] array){}
}
  • 泛型的类型擦除:就是把所有的类型都擦除成原始类型Object类型。如下面代码g1和g2都被擦除成Object类型,而且这个是在编译阶段就已经完成了
GenericMath<Integer> g1 = new GenericMath<Integer>();
GenericMath<Integer> g2 = new GenericMath<Integer>();
System.out.println(g1.getClass()==g2.getClass());

三、泛型方法

  • 上面介绍了如何定义一个泛型类,下面介绍一下如何定义带有简单类型参数的简单方法
class GenericMath<T extends Number>{
    public int sumFunc(T[] array){
            // Number a = new Number();   Object o = new Object();
        int sum = 0;
        for(T val : array){
            sum += val.intValue();
        }
        return sum;
    }
    public <E extends Number> int sumFunc2(E[] array){
        int sum = 0;
        for(E val : array){
            sum += val.intValue();
        }
        return sum;
    }
public static <E extends Comparable<E>> boolean compare(E a, E b){
        return a.compareTo(b) > 0 ? true : false;
    }
}
  • 对于上述代码,可以看到:
  • 1、在定义泛型类的时,T extends Number,这是对T的类型进行设置上界,不然在编译阶段会把T类型擦除成Object类型,从而导致报错。
  • 2、在一个泛型类中,设置多个不同的泛型方法,但是每个泛型方法的作用域必须注意。而且尽量用不同的字母进行区分,一般情况下是T或者E。

四、泛型接口

interface Info24<T> { // 在接口上定义泛型  
    public T getVar(); // 定义抽象方法,抽象方法的返回值就是泛型类型  
}  
// 定义泛型接口的使用
class InfoImp24<T> implements Info24<T> { }

五、注意事项

  • 1、不能直接new泛型类型的对象
//编译器不知道泛型类型T到底是什么类型
T a = new T();
//应该这样定义
GenericMath<Integer> obj1 = new GenericMath<Integer>();
  • 2、不能直接new泛型类型的数组
T[] arr = new T[5];//error   
//等价于
T[] array = (T[])new Object[5];
//因为编译器不知道T是什么类型
  • 3、static方法不能使用泛型类定义的泛型参数T,因为静态方法都需要类型来调用,而不是对象来调用,使用泛型参数T调用,编译器也不知道它是什么类型。
//静态泛型方法
public static <E extends Comparable<E>> boolean compare(E a, E b){
        return a.compareTo(b) > 0 ? true : false;
    }
  • 4、不能定义泛型类的数组
GenericMath<Long>[] g3 = new GenericMath<Long>[5];
  • 这有什么问题呢?因为擦除之后,g3的类型是GenericMath[],在类的内部,泛型类型就是被基类型代替的(默认是Object类型),而对外,所有返回值类型为泛型类型的方法,在真正使用返回值之前,都是会经过类型转换的。
  • “编译的时候通过增加强制类型转换的代码,来避免用户编写出可能引发ClassCastException的代码”。这其实也算是Java引入泛型的一个目的。如果允许了泛型数组,那么编译器添加的强制类型转换的代码就会有可能是错误的。
Integer[] intArray2 = new Integer[10];
//intArray2[0] = new String("hello world");//会报错!
Object[] obj1 = intArray2;
obj1[0] = new String("hello world");//这样就实现了
  • 5、泛型代码需要检查是否需要制定上界
public static <E extends Comparable<E>> boolean compare(E a, E b){
        return a.compareTo(b) > 0 ? true : false;
    }
  • 对于此代码如果不设置Comparable上界就不可以用compareTo方法。
  • 6、两个引用类型互相为继承关系,本来可以基类引用派生类对象的,但是,该两个类型作为泛型类的实例化类型,互相是不能够引用的!