Java基础-核心知识点:方法参数传递机制 (值传递 vs. 引用传递)

这是 Java 基础中一个非常经典且容易混淆的概念,也是面试中必考的知识点。

1. 核心结论:Java 中只有值传递 (Pass by Value)

无论方法参数是基本数据类型还是引用数据类型,Java 在方法调用时,总是将**实际参数的一个副本(一份拷贝)**传递给形式参数。

2. 什么是值传递?(以及基本数据类型的情况)

  • 定义:方法接收到的是实际参数的值的副本。在方法内部对这个副本的任何修改,都不会影响到方法外部的实际参数。
  • 基本数据类型示例
public class PassByValueDemo {

    public static void changePrimitive(int num) {
        System.out.println("进入方法前,num = " + num); // num = 10
        num = 20; // 修改的是 num 的副本
        System.out.println("退出方法前,num = " + num); // num = 20
    }

    public static void main(String[] args) {
        int originalNum = 10;
        System.out.println("调用方法前,originalNum = " + originalNum); // originalNum = 10
        changePrimitive(originalNum);
        System.out.println("调用方法后,originalNum = " + originalNum); // originalNum = 10
    }
}
    • 解释:当 changePrimitive 方法被调用时,originalNum 的值 10 被复制一份,传递给了 numnumoriginalNum 拥有各自独立的内存空间。所以在方法内部修改 num 的值,对 originalNum 没有任何影响。

3. 引用数据类型的传递:依然是值传递 (传递的是引用的副本)

这是最容易产生误解的地方。很多人会认为引用数据类型是“引用传递”,但实际上,Java 传递的依然是引用地址的副本

  • 核心:传递给方法的是对象内存地址的一个副本。这意味着方法内部和外部的引用变量虽然指向了同一个对象,但它们本身是两个独立的引用变量。
  • 引用数据类型示例
class MyObject {
    String value;
    public MyObject(String value) {
        this.value = value;
    }
}

public class PassByReferenceLookalikeDemo {

    public static void changeObjectValue(MyObject obj) {
        System.out.println("进入方法前,obj.value = " + obj.value); // obj.value = "Original"
        obj.value = "Changed"; // 通过副本引用修改了同一个对象内部的状态
        System.out.println("退出方法前,obj.value = " + obj.value); // obj.value = "Changed"
    }

    public static void swapObjects(MyObject obj1, MyObject obj2) {
        System.out.println("进入方法前,obj1.value = " + obj1.value + ", obj2.value = " + obj2.value);
        MyObject temp = obj1;
        obj1 = obj2; // obj1 的副本指向了 obj2 副本指向的对象
        obj2 = temp; // obj2 的副本指向了 obj1 副本最初指向的对象
        System.out.println("退出方法前(方法内部),obj1.value = " + obj1.value + ", obj2.value = " + obj2.value);
    }

    public static void main(String[] args) {
        MyObject myObj = new MyObject("Original");
        System.out.println("调用 changeObjectValue 前,myObj.value = " + myObj.value); // myObj.value = "Original"
        changeObjectValue(myObj);
        System.out.println("调用 changeObjectValue 后,myObj.value = " + myObj.value); // myObj.value = "Changed"
        // 结果显示对象内部状态被修改了,这让人误以为是引用传递

        System.out.println("\n--- 证明是值传递的经典案例:交换引用 ---");
        MyObject a = new MyObject("A");
        MyObject b = new MyObject("B");
        System.out.println("调用 swapObjects 前,a.value = " + a.value + ", b.value = " + b.value); // A, B
        swapObjects(a, b);
        System.out.println("调用 swapObjects 后,a.value = " + a.value + ", b.value = " + b.value); // A, B
        // 结果显示外部的 a 和 b 引用并没有被交换,证明传递的是引用的副本
    }
}
  • 解释
    • changeObjectValue 方法被调用时,myObj 存储的内存地址被复制一份,传递给了 obj。此时,myObjobj 都是独立的引用变量,但它们都指向堆中同一个 MyObject 对象
    • 在方法内部,通过 obj.value = "Changed"; 这种操作,我们是修改了 obj 指向的那个对象内部的 value 字段。由于 myObj 也指向同一个对象,所以从 myObj 来看,对象的内部状态被改变了,这看起来很像“引用传递”。
    • 但通过 swapObjects 示例,可以清晰地证明是值传递。在方法内部,obj1obj2副本被交换了,但方法外部的 ab 原始引用并未受到影响,它们仍然指向最初的对象。这说明,方法改变的只是它自己接收到的引用副本的指向,而非外部原始引用的指向。

4. 总结

Java 中只有值传递 (Pass by Value)

  • 基本数据类型:传递的是值的副本。
  • 引用数据类型:传递的是引用地址的副本。虽然方法内可以通过引用副本修改对象内部状态,但如果修改引用副本本身的指向(例如在方法内 obj = nullobj = new AnotherObject()),不会影响外部的原始引用。
posted @ 2026-01-19 14:04  我是刘瘦瘦  阅读(1)  评论(0)    收藏  举报