美文网首页
JAVA基础-按值传递与按引用传递

JAVA基础-按值传递与按引用传递

作者: 小伙纸2022 | 来源:发表于2022-12-05 10:24 被阅读0次

Java 中的按值传递作为参数传递机制

1. 介绍

将参数传递给方法的两种最普遍的模式是“按值传递”“按引用传递”。不同的编程语言以不同的方式使用这些概念。就 Java 而言,一切都是严格的值传递。下面,我们将说明 Java 如何为各种类型传递参数。

2. 按值传递与按引用传递

现代编程语言中最常见的两种机制是“按值传递”和“按引用传递”。在我们继续之前,让我们先讨论这些:

2.1 值传递

当参数是按值传递时,调用方和被调用方方法对两个不同的变量进行操作,这两个变量是彼此的副本。对一个变量的任何更改都不会修改另一个变量。

这意味着在调用方法时,传递给被调用方方法的参数将是原始参数的克隆。在被调用方方法中所做的任何修改都不会影响调用方方法中的原始参数。

2.2 引用传递

当参数是按引用传递时,调用者和被调用者对同一个对象进行操作。

这意味着当一个变量被引用传递时,对象的唯一标识符被发送到方法。对参数实例成员的任何更改都将导致对原始值进行更改。

3. Java中的参数传递

在 Java 中,原始变量存储实际值,而非原始变量存储引用变量,这些引用变量指向它们所引用的对象的地址。值和引用都存储在堆栈内存中。

Java 中的参数始终按值传递。在方法调用期间,每个参数的副本,无论是值还是引用,都会在堆栈内存中创建,然后传递给方法。

如果是原始的,则简单地将其复制到堆栈内存中,然后将其传递给被调用方方法。如果是非原始类型,则堆栈内存中的应用指向堆中的实际数据。当我们通过对象时,堆栈内存中的引用将复制,并将新引用传递给该方法。

3.1 原始类型传递

Java 编程语言具有八种原始数据类型。原始变量直接存储在堆栈内存中。每当任何原始数据类型的变量作为参数传递时,实际参数都会被复制到形参中,并且这些形参会在堆栈内存中累积自己的空间。

只要该方法正在运行,这些形式参数的生命周期就会持续,在返回时,这些形式参数将从堆栈中清除并被丢弃。

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class JavaPassByValueTests {
    @Test
    public void originalValuesNotModified() {
        int a = 1, b = 2;

        assertEquals(a, 1);
        assertEquals(b, 2);

        numberAddOne(a, b);

        assertEquals(a, 1);
        assertEquals(b, 2);
    }

    private static void numberAddOne(int num1, int num2) {
        num1 += 1;
        num2 += 1;
    }
}

让我们通过分析这些值在内存中的存储方式来尝试理解上述程序中的断言:

  1. "a"和“b”变量是原始类型数据,它们的值存储在堆栈内存中。
  2. 当我们调用numberAddOne()方法时,每个变量的精确副本被创建并存储在堆栈内存中的不同位置。
  3. 对这些副本的任何修改只会影响变量的副本,而不会改变原始变量

3.2 对象传递

在 Java 中,所有对象都动态存储在堆空间中。这些对象是从称为引用变量的引用中引用的。😵😵😵

与 原始类型数据相比,Java 对象分两个阶段存储。引用变量存储在堆栈内存中,它们所引用的对象存储在堆内存中。

每当将对象作为参数传递时,都会创建引用变量的精确副本,该副本指向对象在堆内存中与原始引用变量相同的位置

因此,每当我们在方法中对同一对象进行任何更改时,该更改都会反映在原始对象中。但是,如果我们为传递的引用变量分配一个新对象,那么它就不会反映在原始对象中。🌈

@Test
public void passingObject() {
    Person p1 = new Person(1L, "唐僧");
    Person p2 = new Person(2L, "孙悟空");

    assertEquals(p1.username, "唐僧");
    assertEquals(p2.username, "孙悟空");

    modifyPerson(p1, p2);

    assertEquals(p1.username, "唐三藏");
    assertEquals(p2.username, "齐天大圣");
    
    modifyPersonNo(p1, p2);

    assertEquals(p1.username, "唐三藏");
    assertNotEquals(p2.username, "六耳猕猴");
}

private static void modifyPerson(Person p1, Person p2) {
    p1.setUsername("唐三藏");
    p2.setUsername("齐天大圣");
}

private static void modifyPersonNo(Person p1, Person p2) {
    p1.setUsername("唐三藏");
    p2 = new Person(p2.id, "六耳猕猴");
    p2.id++;
}

我们来分析一下上面程序中的断言。

调用第一个方法修改Person对象时,会创建p1p2这两个引用变量的副本,它们指向相同的原始对象。

调用第二个方法时,也会创建引用变量的副本,但是,p2变量,分配了一个新的对象,和变量副本指向的已经不是同一个原始对象,所以对p2的修改不会改变原始对象。

结语

我们了解到,Java 中的参数传递始终是按值传递。但是,上下文会根据我们处理的是原始数据还是对象而变化:

  1. 对于 原始类型,参数是按值传递的
  2. 对于对象类型,对象引用是按值传递的

🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉

参考资料:https://www.baeldung.com/java-pass-by-value-or-pass-by-reference 以及 https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

相关文章

  • 聊聊Java内部类

    一.磨叽磨叽Java值传递与引用传递 “在Java里面参数传递都是按值传递”即:按值传递是传递的值的拷贝,按引用传...

  • Java值传递

    “在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值...

  • [Java]按值传递/按引用传递?

    先上一段代码 PS: 字符串一旦创建,便不可修改 PPS: JVM内存可分为三个区,堆(Heap),栈(Stack...

  • JS是按值传递还是按引用传递?

    JS是按值传递还是按引用传递? 按值传递 VS. 按引用传递 探究JS值的传递方式 按共享传递 call by s...

  • Java中的参数传递

    为了便于理解,会将参数传递分为按值传递和按引用传递。按值传递是传递的值的拷贝,按引用传递传递的是引用的地址值,所以...

  • Java调用方法时值传递的理解

    Java中方法调用时,没有按引用传递这个说法,只有按值传递。基本类型数据的传递和引用类型数据的传递,根本上都是按值...

  • 按值传递与按引用传递

    按值传递 -- 传递的是参数的值,即参数本身。 按引用传递 -- 传递的是指向参数的值的引用(指针),而不是参数的...

  • 按值传递与按引用传递

    按值传递与按引用传递 按值传递:传入的方法参数是原始数据类型,那么在方法内对该参数做任何处理都不会影响外部参数按引...

  • Java按值传递与按引用传递(区别)

    在C++中我们进行参数传递的时候,往往会遇到按值传递与按引用传递的情况,但是在Java中并没有引用这个概念,在今天...

  • 再学JS--函数参数传递类型

    JavaScript的函数参数传递分为按值传递、按引用传递以及按共享传递。 按值传递 什么是按值传递? 把函数外部...

网友评论

      本文标题:JAVA基础-按值传递与按引用传递

      本文链接:https://www.haomeiwen.com/subject/qxnbfdtx.html