Java中包装类与自定义对象的引用工作机制差异疑问
核心差异原因
你遇到的现象本质是两种操作逻辑的区别,叠加包装类、String的不可变特性共同导致的:
1. 自定义类案例的运行逻辑
你给出的Student类是可变类,可以任意修改对象内部的属性值:
Student s3 = s1; s3.name = "student 3";
这两行代码的执行逻辑是:
- 第一行:让s3和s1两个引用指向堆内存中同一个Student对象
- 第二行:修改当前s3指向的对象内部的name属性,全程没有改变s3的指向
因为两个引用指向同一个对象,所以通过s3修改属性后,s1读取到的自然是修改后的值。
2. 包装类/ String 案例的运行逻辑
Integer、String、Double这类都属于不可变类:类的所有成员属性都被final修饰,对象实例化后没有任何方法可以修改对象内部的数值。
你给出的代码里:
Integer c = a; c = 30;
这两行的执行逻辑是:
- 第一行:让c和a两个引用指向同一个值为10的Integer对象
- 第二行:让c引用本身指向一个新的、值为30的Integer对象,完全没有修改原来的10这个对象的内容
这里的c = 30是Java自动装箱的语法糖,等价于c = Integer.valueOf(30),这个方法只会返回新的Integer实例(小数值会复用缓存对象,但绝对不会修改已有对象的值),所以a还是指向原来的10的实例,c指向新的30的实例,输出自然不同。
验证对比
如果你把自定义的Student类也改成不可变类,就能得到和包装类完全一致的效果:
final class Student{ final int id; final String name; // 只提供构造方法赋值,不提供setter public Student(int id, String name) { this.id = id; this.name = name; } }
这时候你写完Student s3 = s1;之后,根本无法修改s3指向的对象的name属性,只能写s3 = new Student(10, "student 3");让s3指向新对象,此时s1的取值完全不会变化,和包装类的表现完全一致。
内容的提问来源于stack exchange,提问作者Helsinki Red
相关产品推荐
相关产品推荐

