理解Java中的“按值传递”和“按引用传递”

理解java中的“按值传递”和“按引用传递”

当谈到方法参数时,java 编程中最容易被误解的主题之一是“按值传递”和“按引用传递”之间的区别。在这篇博文中,我们将深入探讨这些概念,包括 java 如何实际处理方法参数,并提供说明性代码示例来阐明幕后发生的事情。

“按值传递”和“按引用传递”是什么意思?

按值传递:

在“按值传递”中,方法接收传递给它的参数的实际值的副本。对方法内参数所做的任何修改都不会影响原始参数。

通过参考传递:

在“按引用传递”中,方法接收对参数实际内存位置的引用(或地址)。对参数的修改直接影响原始对象,因为该方法在同一内存上操作。

java 如何处理方法参数?

在java中,所有参数都是按值传递的。但是,此语句可能会产生误导,因为根据参数是基本类型还是对象引用,按值传递的内容会有所不同。

  1. 原始类型:值本身被复制并传递给方法。
  2. 对象(非基元):复制对象的引用并将其传递给方法。虽然引用本身是一个副本,但它仍然指向内存中的同一个对象。

这种区别可能会造成混乱,导致一些开发人员错误地认为 java 支持“按引用传递”。让我们用代码示例来分解它。

按值传递:原始类型

当您将基本类型传递给方法时,java 会创建实际值的副本。方法内参数的更改不会影响原始变量。

public class passbyvaluedemo {
    public static void main(string[] args) {
        int num = 10;
        system.out.println("before method call: " + num); // output: 10
        modifyprimitive(num);
        system.out.println("after method call: " + num); // output: 10
    }

    public static void modifyprimitive(int n) {
        n = 20; // changes the copy, not the original
        system.out.println("inside method: " + n); // output: 20
    }
}

说明:

• num 的值被复制并传递给modifyprimitive 方法。
• 在方法内部,对本地副本(n)进行了更改,但主方法中的 num 保持不变。

按值传递:对象引用

对于对象来说,引用(内存地址)是按值传递的。这意味着该方法对引用指向的同一个对象进行操作,但引用本身是一个副本。让我们来说明一下:

示例1:修改对象状态

class person {
    string name;

    person(string name) {
        this.name = name;
    }
}

public class passbyvalueobject {
    public static void main(string[] args) {
        person person = new person("alice");
        system.out.println("before method call: " + person.name); // output: alice
        modifyobject(person);
        system.out.println("after method call: " + person.name); // output: bob
    }

    public static void modifyobject(person p) {
        p.name = "bob"; // modifies the same object
        system.out.println("inside method: " + p.name); // output: bob
    }
}

说明:

• 复制对 person 对象的引用并将其传递给modifyobject 方法。
• 原始引用和复制引用都指向内存中的同一对象,因此对象状态的更改在方法外部可见。

示例 2:重新分配对象引用

现在让我们看看如果您尝试在方法内重新分配引用本身会发生什么。

public class passbyvaluereassign {
    public static void main(string[] args) {
        person person = new person("alice");
        system.out.println("before method call: " + person.name); // output: alice
        reassignobject(person);
        system.out.println("after method call: " + person.name); // output: alice
    }

    public static void reassignobject(person p) {
        p = new person("charlie"); // reassigns the local copy of the reference
        system.out.println("inside method: " + p.name); // output: charlie
    }
}

说明:

• 引用人员被复制并传递给 reassignobject 方法。
• 在方法内部,本地副本 (p) 被重新分配以指向新对象 (new person("charlie")),但这不会影响 main 方法中的原始引用。
• 主静态中的原始人物引用指向“alice”对象。

揭秘:内存中发生了什么?

原始类型:

• 该值直接存储在与变量关联的内存位置。
• 当传递给方法时,该值将被复制到参数的新内存位置。

对象引用:

对象的引用(内存地址)存储在变量中。
• 当传递给方法时,引用会被复制,因此原始引用和复制的引用都指向堆内存中的同一个对象。

行为可视化

示例:对象引用

Person person = new Person("Alice"); // Memory layout
// Stack (local variables):
// person -> address: 0x1234

// Heap (objects):
// 0x1234 -> Person{name="Alice"}

当传递给方法时:
• 创建一个新引用(例如 p),它也指向 0x1234。

要点

  1. java 始终是“按值传递”。 • 对于基元:复制值本身。 • 对于对象:引用被复制,但两个引用都指向同一个对象。
  2. 修改对象的状态会影响原始对象,因为方法操作于同一个对象。
  3. 在方法内重新分配引用不会影响方法外的原始引用。

通过理解这些细微差别,您将能够更好地推理 java 方法调用并避免程序中的常见陷阱。

以上就是理解Java中的“按值传递”和“按引用传递”的详细内容,更多请关注硕下网其它相关文章!