美文网首页Java面试
值传递和引用传递

值传递和引用传递

作者: EclipseO2 | 来源:发表于2018-08-20 10:45 被阅读8次

值传递

我们可以直接看一个值传递的例子

public void swap(int x, int y) {
    int temp = x;
    x = y;
    y = temp;
}
    
@Test
void testObject() {
    int a = 100;
    int b = 200;
    swap(100, 200);
    System.out.println("a: " + a);
    System.out.println("b: " + b);
}

//输出
a: 100
b: 200

可见,a 和 b 的值在经过“所谓的”交换函数之后,并没能把值交互。这是为什么呢?

这就是因为java是值传递的。也就是说,我们在调用一个需要传递参数的函数时,传递给函数的参数并不是我们传进去的参数本身,而是它的副本。

以这个例子来说,当我们调用 swap 这个函数时,并不是传入的真正的 a 和 b 这两个参数,而是他们俩的复制品,比如我们定义这两个复制品为 x 和 y,此时 x 会指向另一个 100,y 会指向另一个 200。之后在方法 swap 中的所有操作,其实都是基于这两个复制出来的变量 x 和 y 进行着的。尽管 x 和 y 的值确实交换了,但是他们值的改变并不能影响到 a 和 b。

再来看一个例子:

void foo(int val) {
    val = 100;
}

void foo1(String text) {
    text = "win";
}

@Test
public void print() {
    int val = 200;
    foo(val);
    System.out.println(val);
    
    String text = "hello";
    foo1(text);
    System.out.println(text);
}

无可厚非,输出分别是 200 和 hello。可以用图片来描述一下流程

首先,在调用方法之前,会先创建一个形参 val 当调用 foo 函数的时候,实参 val 将自身的值拷贝一份,将拷贝的副本传给形参

当执行函数中的语句时,其实都是对拷贝的那个参数,即形参 val 进行赋值,可以看到,我们将他直接变为了 100,而实际的参数 val,还是原来的 200


引用传递

顾名思义,就是方法的参数是一个类的引用

class People {
    int age;
}

@Test
void testObject() {
    People p1 = new People();
    People p2 = new People();
    p1.age = 10;
    p2.age = 15;
    System.out.println("p1.age: " + p1.age + " p2.age: " + p2.age);
    
    p1 = p2;
    System.out.println("p1.age: " + p1.age + " p2.age: " + p2.age);
    
    p1.age = 30;
    System.out.println("p1.age: " + p1.age + " p2.age: " + p2.age);
}

//输出
p1.age: 10 p2.age: 15
p1.age: 15 p2.age: 15
p1.age: 30 p2.age: 30

通过图示我们可以分析一下

首先在栈中建立两个引用 p1 和 p2,分别指向堆中 new 出来的对象 执行 p1=p2 这个语句,把栈中 p1 指向 p2 在堆中指向的位置,即第二个 People 对象,此时 p1 和 p2 都指向了堆中第二个 People 对象

执行 p1.age=30 这个语句,即把第二个 People 对象的 age 属性变为30,由于 p1 和 p2 都指向这个对象,因此 p1 和 p2 的 age 属性都是15


我们可以再来看一个例子

void foo(StringBuffer stringBuffer) {
    stringBuffer.append("world");
}

@Test
void bufferTest2() {
    StringBuffer sb = new StringBuffer("hello");
    foo(sb);
    System.out.println(sb);
}

输出结果是 helloworld,表明原来的值已被改变。照例,我们画个图

一开始,栈中的 StringBuffer 引用指向堆中的 StringBuffer 对象,该对象里面的值为 "hello" 当使用方法时,形参会先产生一个 StringBuffer 引用 stringBuffer,然后指向堆中的对象

然后调用方法,append 方法直接改变的就是原来 String 的值。可以看到,此时堆中 StringBuffer 对象中的值已经改变,此时两个引用 sb 和 stringBuffer 都指向同一个对象


我们再来看另一个例子

void foo1(StringBuffer stringBuffer) {
    stringBuffer = new StringBuffer("world");
}

@Test
void bufferTest2() {
    StringBuffer sb = new StringBuffer("hello");
    
    foo1(sb);
    System.out.println(sb);
}

此时输出的值没有改变,还是 "hello"。这是为什么呢?

当调用 fool 方法的时候,实际在栈中又新创建了一个 StringBuffer 的引用 stringBuffer,这个引用重新指向了一个新的 StringBuffer 对象。

所以即使当执行方法之后,输出 sb,依旧还是原来的 sb 指向的对象中的值,即 "hello"

相关文章

  • Day12-Java

    值传递和引用传递 值传递是值的拷贝, 引用传递是引用的拷贝 String 类型是引用类型, new String ...

  • Java所有参数-对象引用及基本类型值--都是值传递

    前言 当前主要存在两种传递方式,值传递和引用传递,先简单介绍值传递和引用传递值传递(pass by value)是...

  • Java中的参数传递

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

  • Dart是值传递还是引用传递

    结论:Dart是值传递。 我们先看值传递和引用传递的定义: 值传递和引用传递,属于函数调用时参数的求值策略(Eva...

  • C++基础

    C++ 值传递、指针传递、引用传递详解C++中引用传递与指针传递区别 引用传递和指针传递的区别 引用的规则:(1)...

  • 值传递和引用传递

    值传递 我们可以直接看一个值传递的例子 可见,a 和 b 的值在经过“所谓的”交换函数之后,并没能把值交互。这是为...

  • 值传递和引用传递

    什么是值传递 js是只支持值传递的,举个例子: 此时a的值在函数内是不变的,即复制了一个临时的值,这便是值传递。 ...

  • 值传递和引用传递

    在java中值传递是指传递具体的值,传递的是内容的拷贝,传递后就不关原来的什么事了 引用传递是指传...

  • 值传递和引用传递

    下面有一个代码非常好帮助理解我的理解是:引用在栈中,存储变量堆地址。实际变量在堆中。引用指向变量。方法参数传递的是...

  • 引用传递和值传递

    Java (1)基本数据类型传值,对形参的修改不会影响实参; (2)引用类型传引用,形参和实参指向同一个内存地址(...

网友评论

    本文标题:值传递和引用传递

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