写点什么

Java 是值传递还是引用传递,又是怎么体现的

  • 2024-09-09
    福建
  • 本文字数:5322 字

    阅读完需:约 17 分钟

关于 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:10modifyAndReturn第2次打印int:999------------------------------------modifyAndReturn第1次打印String:TommodifyAndReturn第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)); }
复制代码


执行结果如下


修改前,传参前:1324119927990368553---------------------------修改前,传参后:1324119927990368553---------------------------修改后,传参后:10969792701078694789---------------------------修改后,执行完方法后:1324119927990368553
复制代码


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


下面演示引用类型的另一种情况,一些老铁可能以为是对引用类型本身的修改,其实这是不对的。先定义一个类 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次打印:9903685531096979270107869478918319327241747585824---------------------------第2次打印:9903685531096979270107869478918319327241747585824---------------------------第3次打印:990368553102389292855863868618319327241149319664---------------------------第4次打印:990368553209363181955863868618319327241149319664
复制代码


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


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


文章转载自:比花花解语

原文链接:https://www.cnblogs.com/huajieyu/p/18401887

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Java是值传递还是引用传递,又是怎么体现的_Java_不在线第一只蜗牛_InfoQ写作社区