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

关于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是值传递的,传参的时候并不是把本身传入,而是创建一个副本,当被修改指向的时候不会影响本身,修改属性由于不会修改本身的地址,因此的时候可以应用到本体上。

posted @ 2024-09-07 16:58  比花花解语  阅读(14)  评论(0编辑  收藏  举报