ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【Java】包装类泛型

【Java】包装类泛型

包装类

为什么要有包装类

  • Java 里8 种基本数据类型
    (byte/short/int/long/float/double/char/boolean)不是对象,不继承Object。

  • 但是集合、泛型只能存对象,不能直接放基本类型,所以 Java 为每个基本类型提供了对应的包装类,把基本值包装成对象。


  • 大部分就是首字母大写;只有两个特殊:
    int → Integer
    char → Character


自动装箱 自动拆箱

  • 装箱:基本类型 → 包装对象

    Integer a = 10; // 自动装箱,等价于 Integer a = Integer.valueOf(10);
  • 拆箱:包装对象 → 基本类型
    int b = a; // 自动拆箱,等价于 int b = a.intValue();

Integer 缓存池

  • Integer.valueOf()会缓存-128 ~ 127的 Integer 对象,这个区间内直接复用对象,超出区间新建对象:

    Integer i1 = 100; Integer i2 = 100; System.out.println(i1 == i2); // true,在缓存池里 Integer i3 = 200; Integer i4 = 200; System.out.println(i3 == i4); // false,超出缓存,是两个不同对象
  • 包装类比较值,优先用.equals(),不要用==


包装类的常用作用

  • 放入泛型、集合(List<Integer>,不能写List<int>)
  • 可以存null(基本类型有默认值,不能为 null)
  • 自带很多工具方法:字符串转数字、进制转换等
  • int num = Integer.parseInt("123"); // 字符串转int String s = Integer.toString(456); // 数字转字符串

装箱,拆箱

  • 装箱

    // 手动装箱 int i=10; Integer ii=Integer.valueOf(i)

    装箱:把基本类型 int,包装成 Integer 对象
    valueOf():优先从缓存池-128~127拿现成对象,节省内存

    // 方式2:new Integer(i) 【不推荐,Java9已经废弃】,每次都新建对象,不走缓存 Integer ij = new Integer(i);

    new Integer():强制创建新对象,哪怕值在缓存区间也不复用

  • 拆箱
    // 拆箱 :从Integer对象里取出里面的int值 int j=ii.intValue();
    每个包装类都有对应的xxxValue()方法:
    Integer→intValue()
    Double→doubleValue()
    Character→charValue()
  • 自动装箱、自动拆箱
    // 自动装箱: 等价与 Integer a=Integer.valueOf(10) Integer a=10; // 自动拆箱:等价于 int b=a.intValue(); int b=a;

    写起来更简洁,编译之后本质还是上面的 valueOf() 和 intValue()
    自动装箱只是语法糖,底层调用的就是 valueOf,这也是缓存池生效的前提

  • 重点对比
    Integer i1=100; // 自动装箱 ---> valueOf(100) 缓存里拿 Integer i2=100; System.out.println(i1==i2); // true , 同一个缓存对象 Integer i3=200; // 自动装箱,----> valueOf(200) 超出缓存,新建对象 Integer i4=200; System.out.println(i3==i4); // false ,两个不同对象

    Integer 的缓存数组 cache 只预存了-128 ~ 127之间的对象。
    坑点:
    (a) == 比较的是对象地址;
    (b)比较包装类的值,一定要用 .equals()

面试题

  • Integer a=127; Integer b=127; Integer c=128; Integer d=128; System.out.println(a==b); // true System.out.println(c==d); // false // equals 比较数值,不管是否在缓存区间 System.out.println(c.equals(d)); // true

    (1)Integer a = 127; Integer b = 127;
    a) 这是自动装箱,底层等价于Integer.valueOf(127)。
    b) Java 的Integer内部有一个静态缓存IntegerCache,
    默认缓存范围是-128 ~ 127。
    b) 数字 127 落在缓存区间内,valueOf直接返回缓存里同一个对象。
    d)==对引用类型比较的是对象内存地址,a和b地址相同,所以输出true。
    (2)Integer c = 128;、Integer d = 128;
    a)128 超出了-128--127的缓存范围,Integer.valueOf(128)
    会新建两个不同的 Integer 对象。
    b)c和d是两个独立对象,内存地址不一样,==判断地址不相等,输出false。
    (3)补充
    a)==:基本类型比值;包装类(引用类型)比对象地址
    b)比较包装类里面的数值大小,要用 a.equals(b)

    System.out.println(c.equals(d)); // true,比较内部数值

泛型

  • 背景
    普通类 / 方法只能写死固定类型(基本类型、自定义类),想一套代码适配多种类型就很麻烦,这就是泛型要解决的问题
  • 版本
    泛型是JDK1.5新增语法
  • 通俗理解
    泛型 =适用于很多类型
  • 专业定义
    泛型本质是类型参数化:把类型像参数一样传入,让类、接口、方法可以在不修改源码的情况下,支持多种不同类型

泛型带来的好处

  • 编译期类型检查,减少类型转换异常
  • 避免大量强制类型转换
  • 复用一套代码,适配多种引用类型
  • 泛型不支持基本类型,要用包装类(Integer 代替 int)
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进