Java方法的值传递机制学习笔记

基本概念

形参和实参

  • 形参:在定义方法时,方法名后面括号()中声明的变量称为形式参数,简称形参。
  • 实参:在调用方法时,方法名后面括号()中使用的值、变量、表达式都称为实际参数,简称实参。

值传递规则

  • 规则:实参给形参赋值的过程
    • 如果形参是基本数据类型的变量,则将实参保存的数值赋值给形参
    • 如果形参是引用数据类型的变量,则将实参保存的地址赋值给形参

代码案例

1. 基本数据类型传递示例

public class PrimitiveTypeExample {
    
    public static void modifyValue(int x) {
        System.out.println("方法内修改前 - x = " + x); // 输出:10
        x = 20; // 修改形参的值
        System.out.println("方法内修改后 - x = " + x); // 输出:20
    }
    
    public static void main(String[] args) {
        int num = 10;
        System.out.println("调用方法前 - num = " + num); // 输出:10
        
        modifyValue(num); // 传递的是num的数值副本
        
        System.out.println("调用方法后 - num = " + num); // 输出:10(不变)
    }
}

2. 引用数据类型传递示例

class Person {
    String name;
    int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class ReferenceTypeExample {
    
    // 修改对象状态 - 会影响原始对象
    public static void modifyPerson(Person p) {
        System.out.println("方法内修改前 - " + p.name + ", " + p.age);
        p.age = 30; // 修改对象内容
        p.name = "李四";
        System.out.println("方法内修改后 - " + p.name + ", " + p.age);
    }
    
    // 重新赋值引用 - 不会影响原始引用
    public static void reassignPerson(Person p) {
        System.out.println("重新赋值前 - " + p.name);
        p = new Person("王五", 40); // 创建新对象,p指向新地址
        System.out.println("重新赋值后 - " + p.name);
    }
    
    public static void main(String[] args) {
        Person person = new Person("张三", 25);
        
        System.out.println("=== 测试修改对象状态 ===");
        System.out.println("调用前: " + person.name + ", " + person.age);
        modifyPerson(person); // 传递的是对象地址的副本
        System.out.println("调用后: " + person.name + ", " + person.age);
        // 输出:李四, 30(原始对象被修改)
        
        System.out.println("\n=== 测试重新赋值引用 ===");
        Person person2 = new Person("赵六", 35);
        System.out.println("调用前: " + person2.name);
        reassignPerson(person2); // 传递引用副本
        System.out.println("调用后: " + person2.name); 
        // 输出:赵六(不变,因为方法内重新赋值不影响原始引用)
    }
}

3. 数组传递示例

public class ArrayExample {
    
    // 修改数组元素 - 会影响原始数组
    public static void modifyArray(int[] arr) {
        System.out.println("方法内修改前: " + Arrays.toString(arr));
        if (arr.length > 0) {
            arr[0] = 100; // 修改数组元素
        }
        System.out.println("方法内修改后: " + Arrays.toString(arr));
    }
    
    // 重新赋值数组引用 - 不会影响原始数组引用
    public static void reassignArray(int[] arr) {
        System.out.println("重新赋值前: " + Arrays.toString(arr));
        arr = new int[]{7, 8, 9}; // 创建新数组
        System.out.println("重新赋值后: " + Arrays.toString(arr));
    }
    
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        
        System.out.println("=== 测试修改数组元素 ===");
        System.out.println("调用前: " + Arrays.toString(numbers));
        modifyArray(numbers); // 传递数组地址的副本
        System.out.println("调用后: " + Arrays.toString(numbers));
        // 输出:[100, 2, 3, 4, 5](原始数组被修改)
        
        System.out.println("\n=== 测试重新赋值数组引用 ===");
        int[] numbers2 = {10, 20, 30};
        System.out.println("调用前: " + Arrays.toString(numbers2));
        reassignArray(numbers2);
        System.out.println("调用后: " + Arrays.toString(numbers2));
        // 输出:[10, 20, 30](不变)
    }
}

4. String特殊示例(不可变对象)

public class StringExample {
    
    // String是不可变对象,任何修改都会创建新对象
    public static void modifyString(String str) {
        System.out.println("方法内修改前: " + str);
        str = str + " World"; // 创建新的String对象
        System.out.println("方法内修改后: " + str);
    }
    
    public static void main(String[] args) {
        String message = "Hello";
        System.out.println("调用前: " + message);
        modifyString(message); // 传递String引用副本
        System.out.println("调用后: " + message); // 输出:Hello(不变)
        
        // 验证String的不可变性
        String s1 = "Java";
        String s2 = s1;
        s1 = s1 + " Programming"; // s1指向新对象
        
        System.out.println("s1: " + s1); // Java Programming
        System.out.println("s2: " + s2); // Java(不变)
    }
}

5. 综合测试类

public class ValuePassingTest {
    
    // 基本类型参数
    public static void testPrimitive(int a, double b, boolean c) {
        a = 100;
        b = 200.5;
        c = false;
        System.out.println("方法内 - a=" + a + ", b=" + b + ", c=" + c);
    }
    
    // 引用类型参数
    public static void testReference(List<String> list, StringBuilder builder) {
        list.add("新元素"); // 修改列表内容
        builder.append("追加内容"); // 修改StringBuilder内容
        
        System.out.println("方法内 - list: " + list);
        System.out.println("方法内 - builder: " + builder);
    }
    
    public static void main(String[] args) {
        // 测试基本类型
        int x = 10;
        double y = 20.5;
        boolean z = true;
        
        System.out.println("=== 基本类型测试 ===");
        System.out.println("调用前 - x=" + x + ", y=" + y + ", z=" + z);
        testPrimitive(x, y, z);
        System.out.println("调用后 - x=" + x + ", y=" + y + ", z=" + z);
        
        // 测试引用类型
        System.out.println("\n=== 引用类型测试 ===");
        List<String> stringList = new ArrayList<>(Arrays.asList("A", "B", "C"));
        StringBuilder stringBuilder = new StringBuilder("原始内容");
        
        System.out.println("调用前 - list: " + stringList);
        System.out.println("调用前 - builder: " + stringBuilder);
        testReference(stringList, stringBuilder);
        System.out.println("调用后 - list: " + stringList); // 被修改
        System.out.println("调用后 - builder: " + stringBuilder); // 被修改
    }
}

输出结果示例

=== 基本类型测试 ===
调用前 - x=10, y=20.5, z=true
方法内 - a=100, b=200.5, c=false
调用后 - x=10, y=20.5, z=true

=== 引用类型测试 ===
调用前 - list: [A, B, C]
调用前 - builder: 原始内容
方法内 - list: [A, B, C, 新元素]
方法内 - builder: 原始内容追加内容
调用后 - list: [A, B, C, 新元素]
调用后 - builder: 原始内容追加内容

核心要点总结

  1. 基本数据类型:传递数值副本,方法内修改不影响原始变量
  2. 引用数据类型:传递地址副本,方法内修改对象内容会影响原始对象
  3. 重新赋值引用:方法内重新赋值引用变量不会影响原始引用
  4. String特殊性:作为不可变对象,任何修改都会创建新对象

这些案例清晰地展示了Java值传递机制的特点,帮助理解方法参数传递的本质。

posted @ 2025-10-09 10:13  吹吹风喝喝酒  阅读(20)  评论(0)    收藏  举报