Java 中对象传入方法内赋值后,为何执行完方法后对象的值未改变呢?
问题背景:
昨天测试同事写的接口时候,发现了这样一个问题
上图中 第一步:lhygTaskMode = null ,紧接着传入 checkParam 方法内部,进行赋值。最后方法执行完毕后,lhygTaskMode 依然为 null,这是为什么呢?
问题原因:
因为java只有一种传递参数的方式:值传递。
在值传递中,实参的值被传给形参,方法体内对形参的任何赋值操作都不会影响到实参。
测试用例:
接下来我们简单写个测试用例来看看具体输出。
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Test a = null;
changeObj(a);
System.out.println(a);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
}
执行上面的代码输出结果如下:
可以看到方法内部对象赋值后,是有对象地址输出的,但是方法执行完毕后,源对象 a 依然是 null。
接下来我们再测试一下,修改源对象属性值后的输出结果。
package com.btonline365.support.test;
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
// Test a = null;
// changeObj(a);
// System.out.println(a);
Test a = new Test();
a.setName("王五");
changeObjValue(a);
System.out.println(a.name);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
public static void changeObjValue(Test a) {
a.setName("李四");
System.out.println("changeObjValue>>"+a.name);
}
}
输出如下:
这里属性值由王五变成了李四。
那第二次的测试,修改了形参的属性值,为什么形参就会把实参属性值也顺便修改了呢?
对形参的任何赋值操作都不会影响到实参,但是对于形参的字段,或者元素(假如形参是一个数组)的赋值操作会影响实参。
补充说明:
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
那么,我来给大家总结一下,值传递和引用传递之前的区别的重点是什么。
值传递 | 引用传递 | |
---|---|---|
根本区别 | 会创建副本 | 不创建副本 |
所有 | 函数中无法改变原始对象 | 函数中可以改变原始对象 |
场景说明:
如果你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。
你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。
但是,不管上面那种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。那你说你会不会受到影响?
public static void main(String[] args) {
Test a1 = new Test();
System.out.println("源对象初始地址:"+a1);
changeObj(a1);
System.out.println(a1);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
上面可以看到对象的地址值并没有发生变化。
稍微解释下这张图,当我们在main中创建一个Test对象的时候,在堆中开辟一块内存。然后a1持有该内存的地址 @15db9742 (图1)。当尝试调用changeObj方法,并且a1作为实际参数传递给形式参数a的时候,会把这个地址@15db9742 交给a,这时,a也指向了这个地址(图2)。然后在changeObj方法内对参数进行修改的时候,即a=new Test();,会重新开辟一块 @6d06d69c的内存,赋值给a。后面对a的任何修改都不会改变内存@15db974的内容(图3)。
上面这种传递是什么传递?肯定不是引用传递,如果是引用传递的话,在a=new Test()的时候,实际参数的引用也应该改为指向@15db974,但是实际上并没有。
通过概念我们也能知道,这里是把实际参数的引用的地址复制了一份,传递给了形式参数。所以,上面的参数其实是值传递,把实参对象引用的地址当做值传递给了形式参数。
所以,值传递和引用传递的区别并不是传递的内容。而是实参到底有没有被复制一份给形参。在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。就像钥匙和房子的关系。
所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。
相关文章
- java生成时间戳类型_Java获取当前时间戳的方法有哪些
- java高级工程师_一名Java高级工程师需要学什么?
- java json decode 中文_关于json_decode乱码及NULL的解决方法「建议收藏」
- java 自定义类加载器_JAVA中如何使用应用自定义类加载器「建议收藏」
- Effective-java-读书笔记之对于所有对象都通用的方法
- java并发编程(2):Java多线程-java.util.concurrent高级工具
- Java获取本地IP方法详解编程语言
- Java学习笔记之六java三种循环(for,while,do……while)的使用方法及区别详解编程语言
- Java – 如何通过反射调用对象的方法详解编程语言
- Java 与 Linux 的结合:开启新时代(java和linux)
- Java InetAddress类及其常用方法
- Java curentThread()方法的作用
- Java Set.isEmpty()方法:判断Set集合对象是否为空
- 构建Java应用程序中Redis集群的方法(java连redis集群)
- Java技术封装Redis,打造高效数据处理系统(java封装redis)
- Java实现Redis订阅的简洁方法(javaredis订阅)
- 版本Linux查看Java版本的简单方法(linux 查看java)
- 使用Java连接MySQL数据库的具体操作方法(java连接mysql代码)
- Oracle全面支持Java链技术构建数据库应用(java链oracle)
- 合Java与Oracle联手打造崭新未来(java和oracle联)
- java中计算字符串长度的方法及u4E00与u9FBB的认识
- java写入文件的几种方法分享
- Java中典型的内存泄露问题和解决方法
- 应用Java泛型和反射导出CSV文件的方法
- java中使用数组进行模拟加密的方法