揭秘Java包装类的128陷阱及分析“==”与“equals()”

public class Test {
    public static void main(String[] args) {
        //为什么要有包装类: java说自己是万物皆对象,基本数据类型不能有对象属性,基本数据类型不能方法的调用
        //byte ------------> Byte
        //short ------------> Short
        //int ------------> Integer
        //long ------------> Long
        //float ------------> Float
        //double ------------> Double
        //char ------------> Character
        //boolean ------------> Boolean
        Integer i = 127; // Integer i = Integer.valueOf(127);
        Integer j = 127; // Integer j = Integer.valueOf(127);
        System.out.println(i == j); // True
        Integer k = 128;
        Integer l = 128;
        System.out.println(k == l); //False
        //面试点: 128陷阱
        //总结:我们使用Integer定义的数据会进行自动装箱,自动装箱调用valueOf()方法,该方法会判断我们的入参是否在-128-127之间,如果在这个之间
        // 则会返回一个已经存在的对象的地址(该对象在Catch数组当中,Catch数组是一个从-128-127的数组),不会重新创建对象,否则会重新创建对象
        //包装类的自动拆装箱 :因为有自动拆装箱的存在,所以包装类定义的数据和基本数据类型可以相互转换
        // Integer m = 10; //自动装箱 Integer m = Integer.valueOf(10);
        Integer m = Integer.valueOf(10);
        int a = m; //自动拆箱 int a = m.intValue();
    }
}

一、 包装类的核心作用

Java 号称 “万物皆对象”,但基本数据类型(如 int、double 等)不具备对象的属性和方法调用能力。包装类为每种基本数据类型提供了对应的 “对象化” 类(如Integer对应int),使其能参与面向对象操作(如泛型、集合存储等)。

二、基本数据类型与包装类的映射

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
boolean

Boolean

三、 自动装箱与拆箱

  • 自动装箱:基本数据类型自动转换为对应包装类对象的过程。例如 Integer i = 127; 底层执行 Integer.valueOf(127)
  • 自动拆箱:包装类对象自动转换为对应基本数据类型的过程。例如 int a = m; 底层执行 m.intValue()

四、 Integer 的 “128 陷阱”(面试重点)

Integer.valueOf() 方法在处理 -128~127 范围内的整数时,会直接返回常量池(Cache 数组[-128~127])中已存在的对象引用;若超出该范围,则会新建对象

  • 案例 1:Integer i = 127; Integer j = 127; → i == j 结果为true(二者指向常量池同一对象)。
  • 案例 2:Integer k = 128; Integer l = 128; → k == l 结果为false(二者是不同对象)。

1. 代码与机制解析

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  • 逻辑:判断整数i是否在IntegerCache的默认范围(-128~127)内。若在范围内,返回缓存中已有的对象引用;否则新建Integer对象。

2. IntegerCache 缓存与 “128 陷阱”

场景内存表现==结果
i = 127Integer iInteger j均指向IntegerCache中同一对象(如图示ij引用地址均为0x127true
i = 128超出缓存范围,Integer kInteger l分别新建对象(图示k引用0xacl引用0xcdfalse


五、==与equals()练习与分析

public class Demo {
    /**
     * 自动装箱:基本数据类型------->包装类
     * 自动拆箱:包装类--------->基本数据类型
     * @param args
     */
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        Integer a1 = 10;
        Integer b1 = 10;
        Integer a2 = new Integer(10);
        Integer b2 = new Integer(10);
        System.out.println(a == b);     //T 基本数据类型==比较值是否相等
        System.out.println(a1 == b1);   //T 128陷阱
        System.out.println(a2 == b2);   //F 创建两个不同新的对象
        System.out.println(a1 == a);    //T 这里Integer类型的a1会自动拆箱,转换成int类型 基本数据类型==比较值是否相等
        System.out.println(a1.equals(a)); //T 这里Integer类型的a1会自动拆箱,转换成int类型 基本数据类型==比较值是否相等
        System.out.println(a1 == a2);  //F 两个Integer对象,两个对象地址不同
        System.out.println(a == a2);   //T 自动拆箱
    }
}

1.== 比较规则与场景分析

==在基本数据类型当中比较值是否相同,在引用数据类型当中比较地址是否相同。

比较场景比较规则结果原理说明
int a == int b基本数据类型比较 “值是否相等”T10 和 10 值相等
Integer a1 == Integer b1(值在 - 128~127)引用类型比较 “地址是否相同”,因缓存复用地址T10 在IntegerCache缓存范围内,a1b1指向同一缓存对象
Integer a2 == Integer b2new创建)引用类型比较 “地址是否相同”Fnew会新建对象,a2b2是不同对象
Integer a1 == int a自动拆箱后比较 “值是否相等”Ta1自动拆箱为int,与a的值(10)比较
Integer a1 == Integer a2(缓存对象 vs new对象)引用类型比较 “地址是否相同”Fa1是缓存对象,a2是新对象,地址不同
int a == Integer a2自动拆箱后比较 “值是否相等”Ta2自动拆箱为int,与a的值(10)比较

2.equals() 方法分析

//equals()不能在基本数据类型当中使用,在Object类当中的equals()方法用的是==比较地址
//String类重写了equals(),首先使用==比较地址,如果不相同则再去判断值是否相同。

Integerequals()方法重写的目的是判断 “值是否相等”

Integerequals()方法会先将参数自动拆箱int,再比较值是否相等。因此 a1.equals(a) 结果为Ta1拆箱后值为 10,与a的值 10 相等)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值