Java 值传递 or 引用传递?

createh51个月前 (03-28)技术教程5

Java 方法传参 值传递 or 引用传递?

结论:Java采用的是值传递

先建立一些基础的概念

什么是值传递和引用传递?

  • 值传递(pass by value):是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
  • 引用传递(pass by reference):是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数

Java的数据类型分为两类

  • 基本类型(int float等)
  • 引用类型(string, 数组等, 以及一切类对象)

如下图,展示了两者在内存中存储形式,基本类型存储的是值,而引用类型存储的是地址,该地址指向值所在的内存空间。引用类型有点类似于C语言中的指针。

实践出真知,本文做了三个实验来论证为什么Java是值传递。

实验一:证明基本类型是值传递

先上代码

public class test {

    public static void main(String[] args) {
        int a = 1000;
        changeInt(a);
        System.out.println("(main)a = " + a);
    }

    private static void changeInt(int a) {
        a = 3;
        System.out.println("(changeInt)a = " + a);
    }
}

// 运行代码会得到如下结果
// (changeInt)a = 3
// (main)a = 1000

在代码中,我们向changInt方法传入了变量a,并在方法内部中改变了a的值,但主程序中a的值并没有改变。因此基本类型是值传递。

实验二:引用类型是引用传递?

先上代码

public class test {
    public static void main(String[] args) {
        Student std = new Student();
        std.name = "Nick";
        changeStd(std);
        System.out.println("(main)name = " + std.name);
    }

    private static void changeStd(Student std) {
        std.name = "Paul";
        System.out.println("(change)name = " + std.name);
    }
}

class Student {
    String name;
}

// 运行结果
// (change)name = Paul
// (main)name = Paul

在上段代码中,我们向changeStd方法传入了一个student类实例,并在方法内部中改变了学生类实例中的name字段。从运行的结果我们可以看出主程序中的学生实例的姓名也被改变。难道引用类型采用的是引用传递?当然不是,接下来继续看第三个实验。

实验三:引用类型是值传递?

public class test {
    public static void main(String[] args) {
        Student std = new Student();
        std.name = "Nick";
        changeStd(std);
        System.out.println("(main)name = " + std.name);
    }

    private static void changeStd(Student std) {
        std = new Student();
        std.name = "Paul";
        System.out.println("(change)name = " + std.name);
    }
}

class Student {
    String name;
}

// 运行结果
// (change)name = Paul
// (main)name = Nick

我们改变了方法内部的赋值,我们先重新给std创建了一个新的学生实例,并将名字修改。其结果与实验二相反,方法内部的赋值操作并未改变。难道引用类型又是值传递?

总结

要想理解三个实验的运行结果,其实原理并不复杂。

实验一:下图表示的是,两个变量的内存情况。只有可能是两个a有着不同的地址,方法内部的赋值才不会改变主程序的a值。如果两者是同一内存空间,那么方法内部的修改,必定会影响主程序的a值。

实验二:下图表示的是方法内部还未赋值的时候,两个变量的内存情况。两个变量虽然有着不同的内存空间,但是存储都是Nick的地址,实际指向的是同一个地址空间。有了Nick的存储地址,当然可以方法内部去改变Nick的值。

赋值后

实验三:与实验二相同,在还未创建新的实例时,两者指向的都是Nick。但是在给方法内部的std赋值之后,实际上改变了其存放的地址,将其指向了一个新的对象Paul。

根据三个实验的结果,我们可以论证出Java采用的是值传递,只不过对于基本类型而言,传递的是一个具体的值,而对于引用类型而言传递的也是一个具体的值,只不过这个值是一个地址。而有这个地址,我们可以对地址指向的地址空间进行操作,所以会出现实验二的情况,但是如果我们对值本身进行改变赋值,两者是互不影响的。

看到一个例子说的很形象:

本文来自
https://www.cnblogs.com/XiiX/p/16094857.html

相关文章

如何理解java基础中的Reference和引用类型?

首先要大致了解 Java 的几种引用类型。如下图所示,JDK 1.2 之后新增了 Reference 的概念,给开发人员提供了与 GC 交互的一种渠道。《深入理解 Java 虚拟机》中对于几种引用类型...

详细介绍一下Java中的什么是值传递?什么是引用传递?

Java中的参数传递是通过值传递进行的,即使是对象也是遵循这个规则,想要了解这个原理,首先我们就需要了解什么是值传递,什么是引用传递?值传递值传递是在调用方法的时候,方法接收到的参数是实际参数的一个副...

Java开发者必知的15个核心概念,第8个让你恍然大悟!

你是不是经常在面试中被问到Java的基础概念,却总是回答得不够全面?别担心,今天我们就来聊聊Java开发中那些必须掌握的核心知识点,帮你轻松应对各种技术面试! 1. ClassLoader:Java类...

Java8特性之方法引用

方法引用简介如果在Lambda表达式的具体逻辑处理和某个方法的处理逻辑相同,则可以直接将方法名称指代具体的处理逻辑,从而使得整个Lambda表达式更加的简洁,逻辑更加清晰。比如: System.out...

java注解的原理,作用,特性和使用方法

Java 注解1. 原理Java注解是一种在源代码级别添加元数据的方式,其处理过程分为三个主要步骤:编译时处理:注解信息由编译器读取并生成字节码中的属性。例如,@Override用于检查方法是否正确重...

Java周边:Java密封类:为什么它们如此重要?

你是否曾经因为某个类被意外继承而头疼不已?Java 15 引入的密封类(Sealed Classes),正是为了解决这个问题!它让你能够精确控制哪些类可以继承或实现你的基类,彻底告别“继承失控”的烦恼...