我们提供安全,免费的手游软件下载!

安卓手机游戏下载_安卓手机软件下载_安卓手机应用免费下载-先锋下载

当前位置: 主页 > 软件教程 > 软件教程

Java是值传递还是引用传递?从代码层面来探讨

来源:网络 更新时间:2024-09-08 09:33:18

在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
------------------------------------

从结果可以看出,无论是基本类型还是引用类型,在传入方法的参数值和方法执行后的值是一样的。

接下来,我们换个方法将参数取出并返回。

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

通过返回值,我们可以看到参数的改变被成功地保留了下来。接下来,我们对代码进行进一步测试。

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

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

接下来,我们演示引用类型的另一种情况。

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