Java泛型深入理解

224 阅读5分钟

坚持每天学一点,快乐学习生活成长。

java泛型

java泛型是jdk5引入的一个新特性,泛型提供了编译时类型安全检查的机制,在编译时可以检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为参数。泛型可以用到容器,方法,接口,内部类,抽象类。

泛型的优点

泛型具备以下几大优点:

1. 类型安全:泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

2.消除强制类型转换:泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3.潜在的性能收益:泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。

下面我们针对泛型的类型安全消除强制类型转换优点进行逐点分析:

a.类型安全

类型安全没什么可分析的,一方面帮助我们在一些类型不确定的方法、变量、类代码编写时实现的更简洁,零一方面在编译时编译器会进行类型检查,提醒我们一些常见的错误。

b.消除强制类型转换

我们先看实现的效果,有时候我们会建立一个类TestClass,其有一个方法getObject()会返回不同类型的对象,于是我们在使用时会先通过getObject获取到对象,然后进行强制类型转换。

public class TestCalss {
    public Object getObject() {
        return obj;
        } 
    }
X x = ...;
A a = (A) x.getObject(...);
B b = (B) x.getObject(...);
C c = (C) x.getObject(...);    

看起来很不美观,调用频度高时对性能也有影响。而通过Java泛型可以很好的解决这个问题:

public static <T> T getObjectV2(String type) {
   if (type.equals("A")) {
       return (T)new A();
   }
   if (type.equals("B")) {
       return (T)new B();
   }
   return (T)new Object();
}

public static void main(String[] args) {
   //A a = (A) getObject("A");
   //B b = (B) getObject("B");

   A a = getObjectV2("A");
   B b = getObjectV2("B");
}

可以看到使用泛型后,无需进行强制转换,编译器不会提示错误,其通过泛型的类型擦除实现,可以看下对应的.class文件,可以看到最近class文件中所有泛型信息都会被擦除掉,在生成的字节码中是不包括泛型中的类型信息的。同时java编译器会在编译之前检查泛型的类型,只有通过之后才可以进行编译和擦除

public static <T> T getObjectV2(String type) {
    if (type.equals("A")) {
        return new A();
    } else {
        return type.equals("B") ? new B() : new Object();
    }
}

public static void main(String[] args) {
    A a = (A)getObjectV2("A");
    B b = (B)getObjectV2("B");
}

Java泛型的实现-语法糖

java泛型的实现时由语法糖实现的,下面来了解下语法糖的概念:

语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。Java 中最常用的语法糖主要有泛型、变长参数、条件编译、自动拆装箱、内部类等。虚拟机并不支持这些语法,它们在编译阶段就被还原回了简单的基础语法结构,这个过程成为解语法糖。

泛型是 JDK1.5 之后引入的一项新特性,Java 语言在还没有出现泛型时,只能通过 Object 是所有类型的父类和类型强制转换这两个特点的配合来实现泛型的功能,这样实现的泛型功能要在程序运行期才能知道 Object 真正的对象类型,在 javac 编译期,编译器无法检查这个 Object 的强制转型是否成功,这便将一些风险转接到了程序运行期中。

Java 语言在 JDK1.5 之后引入的泛型实际上只在程序源码中存在,在编译后的字节码文件中,就已经被替换为了原来的原生类型,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList和 ArrayList就是同一个类。所以泛型技术实际上是 Java 语言的一颗语法糖,Java 语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。、

end~ 2022-03-11 繁忙的周五+反复的上海疫情,wish everything well!