信息发布→ 登录 注册 退出

Java 泛型考古 泛型擦除 包装类详细解析

发布时间:2026-01-11

点击量:
目录
  • 一. 什么是泛型
  • 二. 为什么要有泛型 ?
    • 示例
  • 三、泛型考古
    • 四、泛型擦除
      • 五、包装类
        • 六、装箱拆箱

          一. 什么是泛型

          泛型(generic type)其本质是将类型参数化,也就是说所操作的数据类型被指定为一个参数这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

          二. 为什么要有泛型 ?

          之前写过MyArrayList顺序表,这个类当时自己在实现的时候只能用一种类型来表示,也就是用的时候自己实现的MyArrayList只能应用于一种类型,要想应用于其他类型,就得再写一个其他类型的MyArrayList,这样就比较麻烦,而有了泛型之后就很好的解决了这个问题,让类型参数化,使得自己写的MyArrayList可以适用于多种场景

          通过以下代码对比就可发现泛型的方便之处

          示例

          不带泛型

          public class MyArrayList {
              private int[] array;
              private int size;    // 有效数据个数
              public MyArrayList() {
                  this.array = new int[10];
                  this.size = 0;
              }
              public void add(int x) {    // 暂不考虑扩容
                  this.array[size] = x;
                  this.size++;
              }
          }

          带泛型

          import org.omg.CORBA.Object;
          
          public class MyArrayList2<E> {
              // 在类的实现中,可以直接将类当成一种数据类型来使用。在实例化该类的时候这个类型才被确定
              private E[] array;
              private int size;   // 有效数据个数
              public MyArrayList2() {
                  this.array = (E[])new Object[10];   // 注意:Java中泛型不允许定义数组
                  this.size = 0;
              }
              public void add(E e) {    // 不考虑扩容
                  this.array[size] = e;
                  this.size++;
              }
          }
          // 带泛型的顺序表元素类型是一个“变量”
          // E就是变量的名称

          通过上面这两段代码的对比,就可以发现,带泛型的顺序表和不带泛型的顺序表只是表示类型的部分不一样,代码所实现的逻辑是一样的

          类的实例化与使用

          public static void main(String[] args) {
              MyArrayList myArrayList = new MyArrayList();
              myArrayList.add(1);
              myArrayList.add(2);
          																	// 这里其实就相当于是将String类型赋值给E
              MyArrayList2<String> stringMyArrayList2 = new MyArrayList2<String>();    // 等号右边的<>内可以省略
              stringMyArrayList2.add("1");                                           // 要想用基本类型,要写基本类型对应的包装类
              stringMyArrayList2.add("2");
          }

          对于泛型来说,类型是在使用该类时才明确定义出来的

          三、泛型考古

          要知道其实刚开始Java体系中是没有泛型的,是在JDK1.5之后才才有了泛型

          在JDK1.5之前是利用Object引用可以指向任意类型的对象实现类似泛型的效果

          • Object类是所有类的祖先类
          • 上层引用可以指向下层对象

          如下代码:

          public class MyArrayList3 {
              private Object[] array;
              private int size;
              public MyArrayList3() {
                  this.array = new Object[10];
                  this.size = 0;
              }
              public void add(Object e) {
                  this.array[size] = e;
                  size++;
              }
          }

          这种做法的缺点也很明显,就是new了一个MyArrayList,里面打算存int类型的数据,但由于手滑,存入了一个String类型的数据,这样的话编译器是不会报错的,程序也能正常运行,直到需要取list中的元素的时候程序才会抛出异常。

          泛型就很好的解决了这个问题,只要类型不匹配,错误会在第一时间暴露出来

          四、泛型擦除

          虽然在 JDK1.5 之后有了泛型,但其实JDK的底层实现还是用的上面Object来实现的

          如下图

          我们虽然用的是泛型,但其实泛型只存在于编译阶段,在编译过程中也伴随着泛型擦除,在生成.class文件的时候泛型信息就已经不存在了,成了JDK1.5之前的Object方式

          查看MyArrayList的字节码文件就可以看出来

          所以Java的泛型只存在于编译阶段(Java核心原理:Object引用可以指向任意类型的对象)

          五、包装类

          由于8种基本类型不是类型,Java专门为它们定义了各自的包装类

          如下:

          byte java.lang.Byte
          short java.lang.Short
          char java.lang.Character
          int java.lang.Integer
          long java.lang.Long
          float java.lang.Float
          double java.lang.Double
          boolean java.lang.Boolean

          六、装箱拆箱

          Java中提供了便利,如果没有歧义,Java 会帮我们自动装箱,自动拆箱

          Integer a = 10;   // 把int赋值给Integer类型,隐含着发生了装箱过程
          int b = a;      // 把Integer赋值给int类型,隐含着发生了拆箱过程

          隐式装箱和拆箱过程只存在于编译阶段,编译完成就变成显式装箱,显式拆箱了

          在线客服
          服务热线

          服务热线

          4008888355

          微信咨询
          二维码
          返回顶部
          ×二维码

          截屏,微信识别二维码

          打开微信

          微信号已复制,请打开微信添加咨询详情!