关于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. mac 安装homebrew 报443

    描述 macOS安装Homebrew时总是报错(Failed to connect to raw.githubusercontent.com port 443: Connection refused) ...

  2. Spring PropertySource,获取指定application.properties文件

    @PropertySource注解的使用 @PropeertySource,指定加载配置文件 配置文件映射到实体类 使用@Value映射到具体的java属性 CustomConfig.java pac ...

  3. git将某个开发分支最近的提交合并成一个提交

    你可以使用 `git merge --squash` 命令将某个开发分支最近的提交合并成一个提交. 具体步骤如下: 1. 切换到你想要合并的分支上,比如 `develop` 分支: `git chec ...

  4. webpack4.15.1 学习笔记(七) — 懒加载(Lazy Loading)

    懒加载或者按需加载,是一种很好的优化网页或应用的方式.实际上是先把代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或引用另外一些新的代码块.这样加快了应用的初始加载速度,减轻了它 ...

  5. 渐变边框文字效果?CSS 轻松拿捏!

    今天,有个群友问了我这么一个问题,如果不想切图,是否有办法实现带渐变边框的字体效果?如下所示: 本文,就将尝试一下,在 CSS 中,我们可以如何尽可能的实现这种渐变边框字体效果. 元素叠加 首先,比较 ...

  6. Win10下安装LabelImg以及使用--LabelImg

    labelImg是图片标注软件,用于数据集的制作.标注等等.下面介绍labelImg的安装过程. 我用的是anaconda,所以以anaconda prompt作为终端: 在Anaconda Prom ...

  7. 【OracleDB】 08 子查询

    什么是子查询? 子查询是一种常用计算机语言SELECT-SQL语言中嵌套查询下层的程序模块. 当一个查询是另一个查询的条件时,称之为子查询. Oracle的子查询语法公式: SELECT select ...

  8. 【Spring-Security】Re02 基础认证流程

    一.权限认证模拟操作: 编写Security配置类: package cn.zeal4j.configuration; import org.springframework.context.annot ...

  9. 强化学习中经验池的替代设计——A3C算法

    读论文<Asynchronous methods for deep reinforcement learning>有感 ---------------------------------- ...

  10. NVIDIA显卡的利用率“Volatile GPU Util"是什么???

    相关: CPU端多进程/多线程调用CUDA是否可以加速??? 如何实现nvidia显卡的cuda的多kernel并发执行??? ==================================== ...