Java值传递与引用传递核心知识点随堂笔记前言承接Java面向对象、String类系列内容本次笔记彻底讲透Java方法参数传递的核心机制纠正新手最容易踩坑的“Java基本类型值传递、引用类型引用传递”的错误认知完整拆解课堂中的两个核心代码示例结合内存模型讲透底层原理补充面试高频考点适配Java入门复盘与巩固需求。一、核心概念与终极结论1.1 两个核心定义首先必须明确值传递和引用传递的官方定义这是判断Java传递类型的唯一标准值传递Pass By Value方法调用时传递的是实参的副本拷贝而非实参本身。方法内对副本的任何修改都不会影响到方法外部的原始实参。引用传递Pass By Reference方法调用时传递的是实参的内存地址本身而非副本方法内对参数的所有修改都会直接作用到方法外部的原始实参上。1.2 Java的终极结论Java语言中只有值传递没有引用传递。无论参数是基本数据类型还是引用数据类型传递的始终是实参的副本而非实参本身。对于基本数据类型传递的是数据值的副本对于引用数据类型传递的是对象引用地址的副本对应课堂核心句值传递是将值的地址传递过去二、Java内存模型基础铺垫要彻底理解参数传递必须先搞清楚Java中变量在内存中的存储位置这是所有原理的基础栈内存存储方法中的局部变量包括基本数据类型的变量、引用数据类型的变量方法执行完毕后栈帧自动释放。堆内存存储通过new关键字创建的对象本身包括对象的成员属性由JVM垃圾回收器管理。核心关键点引用类型的变量栈中存储的是堆中对象的内存地址变量本身不存储对象内容。比如Student zhangsan new Student(张三,18);栈内存中zhangsan变量存储的是堆中Student对象的内存地址比如0x1堆内存中存储着Student对象本身包含name“张三”、age18两个属性三、基本数据类型的值传递3.1 代码示例publicclassBasicTypeDemo{publicstaticvoidmain(String[]args){inta10;System.out.println(方法调用前a的值a);// 输出10change(a);System.out.println(方法调用后a的值a);// 输出10}// 方法接收int类型参数publicstaticvoidchange(intnum){num20;System.out.println(方法内num的值num);// 输出20}}3.2 执行原理拆解main方法中定义变量a栈中存储a的值为10。调用change(a)时会将a的值拷贝一份副本传递给方法的形参num此时栈中num的值是10和原变量a完全独立。方法内修改num20修改的只是副本的值原变量a的存储空间完全不受影响。方法执行完毕num变量随栈帧释放main方法中的a还是原来的10。这是最典型的值传递副本的修改不会影响原变量。四、引用数据类型的值传递课堂核心示例引用类型的参数传递是新手最容易混淆的知识点核心原因是传递的是地址副本副本和原引用指向堆中的同一个对象修改对象的属性会生效但修改引用本身不会生效。下面完整拆解课堂中的两个核心示例。4.1 示例1修改对象的属性会影响原对象这是课堂中Two类的示例先修正语法错误给出可运行的完整代码packagecom.qcby;/** * 课堂示例修改引用对象的属性 */classTwo{// 成员属性x默认值0bytex;}publicclassReferenceTypeDemo1{publicstaticvoidmain(String[]args){ReferenceTypeDemo1studentnewReferenceTypeDemo1();student.start();}voidstart(){// 创建Two对象栈中two变量存储堆对象的地址比如0x1TwotwonewTwo();System.out.print(two.x );// 输出0// 调用fix方法传递two的地址副本Twotwo2fix(two);System.out.println(two.x two2.x);// 输出42 42}// 形参tt接收的是地址的副本和原two变量指向同一个堆对象Twofix(Twott){// 通过地址副本修改堆中对象的x属性tt.x42;returntt;}}执行流程与内存拆解Two two new Two();栈中创建two变量存储堆中Two对象的地址比如0x1堆中对象的x属性默认值为0。调用fix(two)时会将two变量中存储的地址拷贝一份副本传递给形参tt。此时栈中tt变量存储的地址也是0x1和原two变量指向堆中的同一个对象。执行tt.x 42通过地址副本找到堆中0x1的对象修改其x属性为42。因为原two变量也指向这个对象所以方法外通过two.x获取到的值也变成了42。方法返回tt赋值给two2此时two2和two、tt都指向同一个堆对象所以two2.x也是42。关键误区纠正很多人在这里误以为是引用传递其实不是方法内修改的不是引用本身而是引用指向的堆中对象的内容。如果我们在方法内修改引用本身让tt指向新对象原变量不会受任何影响示例如下Twofix(Twott){// 让tt指向一个全新的对象地址副本变成了0x2ttnewTwo();tt.x42;returntt;}此时执行结果会变成0 0 42原two变量的x还是0因为方法内只是修改了地址副本的指向原two变量的地址完全没变还是指向原来的0x1对象这就是值传递的核心证据。4.2 示例2交换两个对象的引用不会影响原对象这是课堂中Student类的核心示例先修正所有语法错误给出可运行的完整代码packagecom.qcby;/** * 课堂示例交换两个对象的引用 */publicclassStudent{privateStringname;privateintage;// 构造方法publicStudent(Stringname,intage){this.namename;this.ageage;}// 重写toString方法方便打印OverridepublicStringtoString(){returnStudent [namename, ageage];}// 交换两个Student对象的name属性publicstaticvoidchange(Students1,Students2){// 创建临时对象用于交换StudenttempnewStudent(王五,20);// 交换s1和s2的name属性temp.names1.name;s1.names2.name;s2.nametemp.name;}// 进阶交换两个引用本身publicstaticvoidswap(Students1,Students2){Studenttemps1;s1s2;s2temp;}publicstaticvoidmain(String[]args){StudentzhangsannewStudent(张三,18);StudentlisinewStudent(李四,20);System.out.println(调用change前);System.out.println(zhangsan);// 输出Student [name张三, age18]System.out.println(lisi);// 输出Student [name李四, age20]// 调用change方法交换属性Student.change(zhangsan,lisi);System.out.println(\n调用change后);System.out.println(zhangsan);// 输出Student [name李四, age18]System.out.println(lisi);// 输出Student [name张三, age20]// 调用swap方法交换引用本身Student.swap(zhangsan,lisi);System.out.println(\n调用swap后);System.out.println(zhangsan);// 还是Student [name李四, age18]System.out.println(lisi);// 还是Student [name张三, age20]}}核心执行原理拆解1. change方法交换对象的属性会生效main方法中zhangsan变量存储地址0x1对应张三18的对象lisi变量存储地址0x2对应李四20的对象。调用change方法时传递的是0x1和0x2的地址副本形参s10x1s20x2和原变量指向同一个堆对象。方法内通过s1和s2的地址副本直接修改了堆中两个对象的name属性所以方法外的原对象属性也会跟着变化。2. swap方法交换引用本身完全不生效核心证据调用swap方法时传递的还是zhangsan和lisi的地址副本形参s10x1s20x2。方法内的Student temp s1; s1 s2; s2 temp;只是交换了形参s1和s2这两个副本的地址指向s1变成了0x2s2变成了0x1。整个过程main方法中的zhangsan和lisi变量的地址完全没有被修改还是分别指向0x1和0x2的对象所以交换完全不生效。终极结论验证如果Java是引用传递那么swap方法交换引用后main方法中的zhangsan和lisi应该会互换指向但实际完全没有变化这就彻底证明了Java中引用类型传递的也是值地址的副本是值传递而非引用传递。五、新手高频避坑指南永远记住Java只有值传递不要再说“基本类型值传递引用类型引用传递”这是面试高频错误点。区分两个完全不同的操作修改引用指向的对象的属性会影响原对象因为副本和原引用指向同一个堆对象。修改引用变量本身让它指向新对象不会影响原变量因为修改的只是地址副本。不要用“是否修改了原对象内容”来判断传递类型判断的唯一标准是传递的是实参本身还是实参的副本。基本类型的包装类Integer、String等因为是不可变对象方法内修改只会创建新对象不会影响原变量和基本类型表现一致。六、笔记核心总结核心定义值传递传递的是实参的副本引用传递传递的是实参本身的地址Java只有值传递没有引用传递。基本类型传递传递的是数据值的副本方法内修改副本不会影响原变量。引用类型传递传递的是对象引用地址的副本副本和原引用指向堆中的同一个对象修改对象的属性会影响原对象修改引用本身的指向不会影响原变量。核心证据交换两个对象引用的方法无法改变方法外原变量的指向彻底证明Java不是引用传递。内存本质引用变量存储在栈中是堆中对象的地址对象本身存储在堆中所有指向该地址的引用都能修改堆中的对象内容。