关于Java是值传递还是引用传递,可以从代码层面来实现一下拿到结果

执行下面的代码:

    public static void main(String[] args) {
int num = 10;
String name = "Tom";
modify(num, name);
System.out.println("第3次打印int:" + num);
System.out.println("第3次打印String:" + name);
System.out.println("------------------------------------");
} public static void modify(int n, String str){
System.out.println("第1次打印int:" + n);
System.out.println("第1次打印String:" + str);
System.out.println("------------------------------------"); // 尝试在方法内部修改传进来的参数
n = 999;
str = "ABC";
System.out.println("第2次打印int:" + n);
System.out.println("第2次打印String:" + str);
System.out.println("------------------------------------");
}

打印出来的结果如下:

第1次打印int:10
第1次打印String:Tom
------------------------------------
第2次打印int:999
第2次打印String:ABC
------------------------------------
第3次打印int:10
第3次打印String:Tom
------------------------------------

可以看到无论是基本类型还是引用类型,传参数进去的时候的值和执行完modify方法后的值是一样的,也就是第1次打印和第三次打印是一样的。可是为什么明明在第2次已经修改成功了,第3次却又变回去了呢?

尝试换个方法把参数拿出来,

    public static void main(String[] args) {
int num = 10;
String name = "Tom";
int modifiedNum = modifyAndReturn(num);
String modifiedName = modifyAndReturn(name);
System.out.println("打印num:" + num);
System.out.println("打印name:" + name);
System.out.println("------------------------------------");
System.out.println("打印modifiedNum:" + modifiedNum);
System.out.println("打印modifiedName:" + modifiedName);
} public static int modifyAndReturn(int n){
System.out.println("modifyAndReturn第1次打印int:" + n); // 尝试在方法内部修改传进来的参数
n = 999;
System.out.println("modifyAndReturn第2次打印int:" + n);
System.out.println("------------------------------------");
return n;
} public static String modifyAndReturn(String str){
System.out.println("modifyAndReturn第1次打印String:" + str); // 尝试在方法内部修改传进来的参数
str = "ABC";
System.out.println("modifyAndReturn第2次打印String:" + str);
System.out.println("------------------------------------");
return str;
}

得到的结果为

modifyAndReturn第1次打印int:10
modifyAndReturn第2次打印int:999
------------------------------------
modifyAndReturn第1次打印String:Tom
modifyAndReturn第2次打印String:ABC
------------------------------------
打印num:10
打印name:Tom
------------------------------------
打印modifiedNum:999
打印modifiedName:ABC

可以看到通过return出来的值,的确是被改变了的,那又是为什么导致这个改变没有应用到参数本体呢?修改下代码再次测试

public static void main(String[] args) {
int num = 10;
String name = "Tom";
// 打印num和str的地址
System.out.println("修改前,传参前:");
System.out.println(System.identityHashCode(num));
System.out.println(System.identityHashCode(name)); System.out.println("---------------------------");
printAddr(num, name); System.out.println("---------------------------");
System.out.println("修改后,执行完方法后:");
System.out.println(System.identityHashCode(num));
System.out.println(System.identityHashCode(name));
} public static void printAddr(int n, String str){
// 打印n和str的地址
System.out.println("修改前,传参后:");
System.out.println(System.identityHashCode(n));
System.out.println(System.identityHashCode(str)); n = 999;
str = "ABC"; // 打印n和str的地址
System.out.println("---------------------------");
System.out.println("修改后,传参后:");
System.out.println(System.identityHashCode(n));
System.out.println(System.identityHashCode(str));
}

执行结果如下

修改前,传参前:
1324119927
990368553
---------------------------
修改前,传参后:
1324119927
990368553
---------------------------
修改后,传参后:
1096979270
1078694789
---------------------------
修改后,执行完方法后:
1324119927
990368553

可以看到传参进来的参数地址是和外部定义的地址是同一个,但是修改之后会指向另一个新的地址,导致原来地址上的数据不会受到影响,这其实是一个保护机制,防止参数传入方法内被篡改指向。

下面演示引用类型的另一种情况,一些老铁可能以为是对引用类型本身的修改,其实这是不对的。

先定义一个类Person

class Person{
private String name;
private int age; public Person(String name, int age) {
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

执行下面的代码,可以看到传进去的参数的属性被改变


public static void main(String[] args) {
Person person = new Person("Rosy", 24);
String [] strings = {"AAA", "BBB", "CCC"};
System.out.println("第1次打印:");
System.out.println(person);
System.out.println(Arrays.toString(strings)); modifyObjAndPrintValue(person, strings); System.out.println("---------------------------");
System.out.println("第4次打印:");
System.out.println(person);
System.out.println(Arrays.toString(strings));
} public static void main5(String[] args) {
Person person = new Person("Rosy", 24);
String [] strings = {"AAA", "BBB", "CCC"};
System.out.println("第1次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings)); modifyObj(person, strings); System.out.println("---------------------------");
System.out.println("第4次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings));
} public static void modifyObjAndPrintValue(Person person, String [] strings){
System.out.println("---------------------------");
System.out.println("第2次打印:");
System.out.println(person);
System.out.println(Arrays.toString(strings)); person.setAge(1024);
person.setName("ABC");
strings[0] = "XXX"; System.out.println("---------------------------");
System.out.println("第3次打印:");
System.out.println(person);
System.out.println(Arrays.toString(strings));
}

执行结果为

第1次打印:
Person{name='Rosy', age=24}
[AAA, BBB, CCC]
---------------------------
第2次打印:
Person{name='Rosy', age=24}
[AAA, BBB, CCC]
---------------------------
第3次打印:
Person{name='ABC', age=1024}
[XXX, BBB, CCC]
---------------------------
第4次打印:
Person{name='ABC', age=1024}
[XXX, BBB, CCC]

从结果可以发现,Person对象的属性都被修改,String数组的元素也被修改,说明参数里对属性或数组的修改是会影响对象本身的,具体可以打印地址再查看一下:


public static void main(String[] args) {
Person person = new Person("Rosy", 24);
String [] strings = {"AAA", "BBB", "CCC"};
System.out.println("第1次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings));
System.out.println(System.identityHashCode(strings[0])); modifyObjAndPrintAddr(person, strings); System.out.println("---------------------------");
System.out.println("第4次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings));
System.out.println(System.identityHashCode(strings[0]));
} public static void modifyObjAndPrintAddr(Person person, String [] strings){
System.out.println("---------------------------");
System.out.println("第2次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings));
System.out.println(System.identityHashCode(strings[0])); person.setAge(1024);
person.setName("ABC");
strings[0] = "XXX"; System.out.println("---------------------------");
System.out.println("第3次打印:");
System.out.println(System.identityHashCode(person));
System.out.println(System.identityHashCode(person.getAge()));
System.out.println(System.identityHashCode(person.getName()));
System.out.println(System.identityHashCode(strings));
System.out.println(System.identityHashCode(strings[0]));
}
第1次打印:
990368553
1096979270
1078694789
1831932724
1747585824
---------------------------
第2次打印:
990368553
1096979270
1078694789
1831932724
1747585824
---------------------------
第3次打印:
990368553
1023892928
558638686
1831932724
1149319664
---------------------------
第4次打印:
990368553
2093631819
558638686
1831932724
1149319664

从地址上可以看到,person和strings的地址一直没有变过。而在参数内部修改的person属性和数组元素,会对这部分成员的地址进行修改,并且会应用到对象本体上。

总结下来就是,无论传的是基本类型还是引用类型,只要在方法内部尝试改变参数地址的,都只能在方法内部使用,不会影响本体,而在方法内部改变属性的,会把对应的改变应用到本体上。所以Java是值传递的,传参的时候并不是把本身传入,而是创建一个副本,当被修改指向的时候不会影响本身,修改属性由于不会修改本身的地址,因此的时候可以应用到本体上。

Java是值传递还是引用传递,又是怎么体现的的更多相关文章

  1. Java是值传递还是引用传递?

    Java的值传递和引用传递在面试中一般都会都被涉及到,今天我们就来聊聊这个问题.这个问题一般是相对函数而言的,也就是Java中所说的方法参数,那么我们先来回顾一下在程序设计语言中有关参数传递给方法的两 ...

  2. 堆栈详解 + 彻底理解Java的值传递和引用传递

    本文旨在用最通俗的语言讲述最枯燥的基本知识 学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨 ...

  3. Java的值传递和引用传递的说法

    学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨论的话题又是充满争议:有的论坛帖子说Java ...

  4. Java 值传递 or 引用传递?

    Java 方法传参 值传递 or 引用传递? 结论:Java采用的是值传递 先建立一些基础的概念 什么是值传递和引用传递? 值传递(pass by value):是指在调用函数时将实际参数复制一份传递 ...

  5. Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义

    一.Java中什么叫做引用类型变量?引用:就是按内存地址查询       比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...

  6. java中值传递和引用传递

    最近工作中使用到了值传递和引用传递,但是有点懵,现在看了下面的文章后清晰多了.一下是文章(网摘) 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public clas ...

  7. Java中的值传递和引用传递

    这几天一直再纠结这个问题,今天看了这篇文章有点思路了,这跟C++里函数参数为引用.指针还是有很大区别. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里 ...

  8. java的值传递和引用传递

    昨天博主在对于值传递和引用传递这里栽了一个大坑啊,导致一下午时间都浪费在这里,我们先说下值传递和引用传递java官方解释: 值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对 ...

  9. java中方法的参数传递机制(值传递还是引用传递)

    看到一个java面试题: 问:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?  答:是值传递.Java 编程语言只有值传递参 ...

  10. java 对象传递 是 值传递 还是 引用传递?

    这个问题说实话我感觉没有太大的意义. 按第一印象和c++的一些思想去理解的话对象传递是引用传递,因为传递过去的对象的值能被改变. 但是又有很多人,不知道从哪里扣出来一句,java中只有值传递,没有引用 ...

随机推荐

  1. python配置国内pypi镜像源操作步骤

    使用pip config命令设置默认镜像源,使用国内的源,提高安装速度 操作步骤 临时方式pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/si ...

  2. Mysql实现主从复制(一主双从)

    一.环境介绍 LNMP(centos7,mysql5.6) vmware workstation pro配置了3个虚拟机,均安装了LNMP环境: master:  192.168.0.105 slav ...

  3. Python 基于lxml.etree实现xpath查找HTML元素

    基于lxml.etree实现xpath查找HTML元素 By:授客 QQ:1033553122 #实践环境 WIN 10 Python 3.6.5 lxml-4.6.2-cp36-cp36m-win_ ...

  4. 怎么使用github action定时运行js脚本?

    github action是使用yaml文件来做到CI/CD的,文件位置存放在 .github/workflows,yaml文件内容如下: name: ncatest.cx.js on: push: ...

  5. Telegram手机号码反查工具

    Telegram手机号码反查工具 项目地址:https://github.com/bellingcat/telegram-phone-number-checker v1.2.1版本 要求python的 ...

  6. 如何在Linux云服务器上通过Docker Compose部署安装Halo,搭建个人博客网站?

    目录 前置步骤 环境搭建 创建容器组 在系统任意位置创建一个文件夹 创建docker-compose.yaml 启动 Halo 服务 配置反向代理以及域名解析 Halo初始化页面. 更新新版本的hal ...

  7. 【Java】PDF模板生成PDF文档

    一.需求背景 客户要求一份文书,文书内容有一些表单项,例如: 1.基本的是和否 (单选框或复选框) 2.备注内容(纯文本信息) 3.单位,机构组织,人员,字典项(下拉选择) 4.用户数字签名(图片信息 ...

  8. 【SpringMVC】11 拦截器

    拦截器是AOP具体的应用 只能使用SpringMVC自己的组件有效 之拦截访问控制器方法的请求, 如果访问的是jsp.html.css.img.js这一类的静态资源,则不会拦截 演示: 编写一个拦截器 ...

  9. 【Dos-BatchPrograming】02

    学习参考: https://www.bilibili.com/video/BV1Qv411q7bN?p=2 --1.算数运算 使用Windows终端进行运算操作时需要声明对应的命令: set /a 运 ...

  10. 家庭局域网中电脑唤醒 —— WOL远程唤醒(python实现)

    相关: https://blog.csdn.net/hih30250/article/details/136342258 在WOL介绍里说过WOL数据包的最简格式是由6个字节的255和目标计算机的48 ...