多图证明,Java到底是值传递还是引用传递?

开发 后端
开篇先来曝答案,在 Java 语言中,本质只有值传递,而无引用传递,解释和证明详见正文。说到值传递和引用传递我们不得不提到两个概念:值类型和引用类型。

 [[340326]]

本文转载自微信公众号「Java中文社群」,作者磊哥。转载本文请联系Java中文社群公众号。  

开篇先来曝答案,在 Java 语言中,本质只有值传递,而无引用传递,解释和证明详见正文。

说到值传递和引用传递我们不得不提到两个概念:值类型和引用类型。

1.值类型

通俗意义上来说,所谓的值类型指的就是 Java 中的 8 大基础数据类型:

  • 整数型:byte、int、short、long
  • 浮点型:float、double
  • 字符类型:char
  • 布尔类型:boolean

 

从 JVM 层面来讲:所谓的值类型指的是在赋值时,直接在栈中(Java 虚拟机栈)生成值的类型,如下图所示:

 

2.引用类型

引用类型是指除值类型之外的数据类型,比如:

  • 接口
  • 数组
  • 字符串
  • 包装类(Integer、Double...)

 

从 JVM 的层面来讲,所谓的引用类型是指,在初始化时将引用生成栈上,而值生成在堆上的这些数据类型,如下图所示:

3.值传递

值传递(Pass By Value)指的是方法传参时,传递的是原内容的副本,因此对副本进行如何修改都不会影响原内容。

实现代码如下:

  1. public class PassTest { 
  2.     public static void main(String[] args) { 
  3.         int age = 18; 
  4.         System.out.println("调用方法前:" + age); 
  5.         intTest(age); 
  6.         System.out.println("调用方法后:" + age); 
  7.     } 
  8.  
  9.     private static void intTest(int age) { 
  10.         age = 30; 
  11.         System.out.println("方法中修改为:" + age); 
  12.     } 

程序的执行结果为:

调用方法前:18

方法中修改为:30

调用方法后:18

从上述结果可以看出,在方法中修改参数并未影响原内容,我们把这种传参方式称之为值传递。

4.引用传递

引用传递(Pass By Reference)指的是方法传参时,传递的是参数本身,因此对参数进行任意修改都会影响原内容。

模拟“引用传递”的实现代码如下:

  1. public class PassTest { 
  2.     public static void main(String[] args) { 
  3.         char[] name = {'磊''哥'}; 
  4.         System.out.println("调用方法前:" + new String(name)); 
  5.         paramTest(name); 
  6.         System.out.println("调用方法后:" + new String(name)); 
  7.     } 
  8.     private static void paramTest(char[] n) { 
  9.         n[1] = '神'
  10.         System.out.println("方法中修改为:" + new String(n)); 
  11.     } 

程序的执行结果为:

调用方法前:磊哥

方法中修改为:磊神

调用方法后:磊神

从上述的结果可以看出在 paramTest 方法中修改了参数之后,在 main 方法中再打印参数时,发现参数的值也跟着发生了改变,那么似乎我们可以得出结论,Java 中貌似也有“引用传递”,然而实事并如此,我们接着看。

5.真假“引用传递”

我们给上面的代码添加一行,如下所示:

  1. public class PassByValue { 
  2.     public static void main(String[] args) { 
  3.         char[] name = {'磊''哥'}; 
  4.         System.out.println("调用方法前:" + new String(name)); 
  5.         paramTest(name); 
  6.         System.out.println("调用方法后:" + new String(name)); 
  7.     } 
  8.     private static void paramTest(char[] n) { 
  9.         n = new char[2]; // 添加此行代码 
  10.         n[1] = '神'
  11.         System.out.println("方法中修改为:" + new String(n)); 
  12.     } 

程序的执行结果为:

调用方法前:磊哥

方法中修改为:神

调用方法后:磊哥

从上述结果可以看出,当我们在 paramTest 方法中添加 new char[] 之后,“引用传递”就突然变值传递了?为什么?

这是因为,在 Java 语言中本质上只有值传递,也就说 Java 的传参只会传递它的副本,并不会传递参数本身。

前面那个带引号的“引用传递”其实只是传递了它的引用副本,如下图所示:

 

PS:《Java虚拟机规范》中对 Java 堆的描述是:“所有的对象实例以及数组都应当在堆上分配”。

所以我们在调用 new char[] 之后,可以看出 n 对象有了新地址,而原内容并未被修改,如果按照引用传递的思路来看的话,不管执行任何方式的修改都会改变原内容,因此我们可以更加确认 Java 语言中只有值传递,如下图所示:

 

总结

通过本文的内容,我们可以得出:在 Java 语言中只有值传递,方法传参时只会传递副本信息而非原内容。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据,如下图所示:

 

 

 

 

责任编辑:武晓燕 来源: Java中文社群
相关推荐

2022-11-02 15:00:03

Java值传递引用传递

2022-07-29 08:05:31

Java值传递

2023-11-15 09:14:27

Java值传递

2015-09-08 10:16:41

Java参数按值传递

2016-09-18 19:07:33

Java值传递引用传递

2024-09-04 01:36:51

Java对象传递

2018-10-09 15:26:19

JavaPython语言

2018-09-26 14:17:00

编程语言JavaPython

2009-08-17 14:48:44

Java参数传递机制

2020-10-19 09:51:18

MYSQL知识数据库

2015-04-21 09:20:40

SwfitObject—C

2023-11-29 09:47:11

C++对象

2024-03-28 13:13:00

Htmx前端开发框架

2011-09-05 10:30:51

重构代码库业务模型

2017-08-09 08:43:02

公有云趋势声势

2012-02-21 14:04:15

Java

2014-11-17 10:03:23

OpenStack

2022-08-18 23:13:25

零信任安全勒索软件

2020-08-31 19:19:27

TCPUDP视屏面试

2021-12-09 20:16:26

无线核心网传输
点赞
收藏

51CTO技术栈公众号