java采用按值传递,传递对象时实为传递堆中地址值;引用变量存栈,对象存堆,类信息存方法区;修改对象内容可见因共享堆地址,重赋引用不影响原变量;无引用指向时对象成垃圾待gc回收。

Java里没有真正的“引用传递”,只有“按值传递”,但传递的这个“值”对对象来说是内存地址。理解这点,就抓住了对象行为和内存分配的核心。
引用变量存在哪?对象又在哪?
这是最常混淆的起点。简单说:
- 引用变量(比如 String s、List list)本身存放在栈中,它只是一个4字节或8字节的地址值(取决于JVM指针压缩是否开启);
- new出来的对象(包括数组)真实数据都存在堆中,堆是线程共享区域,由GC统一管理;
- 类的结构信息(方法字节码、字段定义、常量池等)存在方法区(JDK 8+叫元空间),只加载一次,不随对象数量增加而重复占用内存。
为什么改对象内容,外面能看到?
因为形参拿到的是实参引用的“副本地址”,两个引用变量指向堆中同一个对象。例如:
StringBuilder sb = new StringBuilder("a");
modify(sb);
System.out.println(sb.toString()); // 输出 "ab"
其中 modify 方法内部执行 sb.append("b"),实际是在堆中那个 StringBuilder 实例上追加字符——不是复制对象,而是操作原对象。
注意:如果在方法内让引用指向新对象,比如 sb = new StringBuilder("c"),这只会改变形参变量的地址值,不影响原始引用。
基本类型和引用类型传参的区别
本质都是“值传递”,区别在于传的值代表什么:
- int、boolean 等基本类型:传的是数值本身(如 10、true),方法内修改不影响调用方;
- String、ArrayList、自定义对象等引用类型:传的是堆中对象的地址值,方法内通过该地址修改对象状态(如 add()、set()、append()),调用方可见;
- 不可变对象(如 String、Integer):看似没变,其实是创建了新对象并让引用指向它,原引用仍指向旧对象——所以“修改” String 实际是重新赋值,不影响外部。
什么时候对象会被回收?
当堆中的某个对象**不再有任何引用变量指向它**时,就成了垃圾。常见场景:
- 局部引用变量超出作用域(方法执行结束,栈帧弹出);
- 显式赋值为 null(
obj = null); - 集合中移除元素后,若无其他引用,该元素对象可能被回收;
- 弱引用(WeakReference)、软引用(SoftReference)关联的对象,在GC策略下更易被回收。
GC不会立即释放内存,但会标记并择机清理——这也是为什么不能依赖 finalize 或假设对象“马上消失”。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











