JAVA泛型分析

1.泛型简单分析

声明:本文是我对泛型的一些理解,主要的是分析,而不是具体应用,所以讲的并不是面面俱到,具体的实现和用法可以参考具体的API文档。

首先我们看一下下面这段代码

var list = new Array();
list.push(1);
list.push("test")
for(var m in list){
       alert(list[m]+1);
}

上面的JavaScript代码是将集合中的值都加上1后弹出,可以看到结果弹出2和弹出 hello1,JavaScript是弱类型语言,可以通过这种方式处理所有类型数据,但是我们再看一下下面这段代码:

public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(1);
        list.add("test");
        for (int i=0; i

上面代码是想将list集合中的int类型的值都加1后输出,但是list集合中存储的是Object的子类,所以当遇到String类型的数据进行加1后就会抛出java.lang.ClassCastException异常。Java 是强类型语言,所以不能对所有类型的值进行加1操作。那解决的方法可以是先通过判断类型然后再进行操作,如下代码

for (int i=0; i

但是如果之后想要对list集合里面的其它类型进行操作时,那将会进行很多判断,这样写出的代码质量和可阅读性就会很差,于是人们发明出泛型这个东西。

2.泛型是什么

  • 泛型从字面上理解可以认为指的是一种类型,泛型的出现就是为了解决上面问题的存在,泛型限定只能存储一种类型,泛型的出现可以减少ClassCastException异常,使得代码可读性提高,如下代码:
public static void main(String[] args) {
        ArrayList list = new ArrayList< Integer>();
        list.add(1);
        //list.add("test");编译时候不通过,编译器报错不能接收String类型对象
        for (int i=0; i
  • 这样通过ArrayList就限定了集合中只能存储Integer类型的值,再对集合中的元素进行加1时就不会报错,这就是泛型的体现。泛型可以分为泛型类、泛型方法、泛型接口。

3.泛型类

  • 泛型类的形式为 类名,T就是代表一种类型,如下
public class GenericDemo {
    public static void main(String[] args) {
        GenericDemo stringGenericDemo = new GenericDemo< String >();
        GenericDemo integerGenericDemo = new GenericDemo< Integer >();
        System.out.println(stringGenericDemo.getClass()==integerGenericDemo.getClass());
    }
}

如上代码所示,GenericDemo类分别限定为Integer和String类,GenericDemo中的T就代表了Integer和String这些类型。最后比较两种类型的Class,发现结果为true,这就引出了泛型擦除也称类型擦除。

  • 泛型擦除是指在编译的时候,编译器将所有类型都编译成Object,我们查看下上面代码生成的字节码

JAVA泛型分析_第1张图片

那么,泛型在运行的时候是怎样判断原来的类型呢?其实泛型类实例可以如下定义GenericDemo stringGenericDemo = new GenericDemo< >();后面的<>里面可以不用指定类型,默认为前面引用对象类型,所以可以通过指定引用对象类型,而不用指定new对象中的类型。如果下面这种形式编译器就会报错不通过。
GenericDemo stringGenericDemo = new GenericDemo();

  • 注意,泛型擦除后T的类型都变成了Object类型,这种说法不完全正确,当我们通过GenericDemo这种方式定义类时候,得到如下字节码:

JAVA泛型分析_第2张图片

T extends String代表T的上限是String类型,如果没有指定上限,那么T会被转换成Object类型。extends指明了T的上限,super关键字可以指明T的下限,如下代码:

List list = new ArrayList;//List ,只允许泛型为T及T的子类引用调用
List< ? super Integer> list2 = new ArrayList;//List,只允许泛型为T及T的父类引用调用
  • 这里还需要注意的一点是,泛型没有泛型数组的形式,因为泛型在编译后都是Object类型,如果存在泛型数组(GenericDemo[] GenericDemo[]),那么在类型擦除后变成GenericDemo[],这样就可以存储各种类型的数据了,但是数组在声明的时候就已经确定类型了,这时候如果存储不同类型就会报错,这就又回到了没有泛型的时候带来的CaseClassException类型转换异常。

4.泛型方法

  • 泛型方法的形式如下
public static  void genericMethod(T t) {//这里的t就是根据传进来的参数来决定类型
    System.out.println(t);
}

泛型方法可以独立存在,也就是不依赖于泛型类,这里不做过多说明。但这里要注意的一点是不能有如下的方法参数,因为在java中,方法名称相同,参数数目或类型不同叫做方法重载,但是泛型在类型擦除后里面的方法类型就相同了,编译器就会报错,所以要注意。

genericMethod(List t) 
genericMethod(List t) 

5.泛型接口

  • 泛型接口定义形式如下:
public interface GenericInterface { 
    T print(T e); 
}

这里不做其它说明。

你可能感兴趣的:(java基础)