深入理解--Java按值传递和按引用传递

2024-09-04 01:58

本文主要是介绍深入理解--Java按值传递和按引用传递,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

最近刷牛客网上的题目时碰到不少有关Java按值传递和按引用传递的问题,这种题目就是坑呀,在做错了n次之后,查找了多方资料进行总结既可以让自己在总结中得到提高,又可以让其他人少走弯路。何乐而不为?

Java按值传递和按引用传递

首先问一句:Is Java “pass-by-reference” or “pass-by-value”? Java到底是按值传递还是按引用传递的呢?国外的网站上关于这个问题的讨论非常之多。官方答案:The Java Spec says that everything in Java is pass-by-value. There is no such thing as “pass-by-reference” in Java. 官方的说法是在java中只有按值传递,并没有所谓的按引用传递。

基本数据类型的按值传递

java数据类型可以分为两大类:基本类型(primitive types)和引用类型(reference types)。primitive types 包括boolean类型以及数值类型(numeric types)。numeric types又分为整型(integer types)和浮点型(floating-point type)。整型有5种:byte short int long char(char本质上是一种特殊的int)。浮点类型有float和double。关系整理一下如下图:

这里写图片描述
例1

public class Swap {public static void main(String[] args) {int x = 10;int y = 20;swap(x, y);System.out.println("x(2) = " + x);System.out.println("y(2) = " + y);}public static void swap(int x, int y) {int temp = x;x = y;y = temp;System.out.println("x(1) = " + x);System.out.println("y(1) = " + y);}
}/*输出x(1) = 20y(1) = 10x(2) = 10y(2) = 20*/

上面程序main函数调用swap函数来交换 x,y的值,然而调用函数之后发现main中x,y的值并未交换。包括在Java api中找不到一个可以交换两个变量的方法。这与Java语言的特性有关。通过一个图就可以知道上面程序的运行结果了。

这里写图片描述
由上图可知,main函数中的x,y和swap函数中的x,y分别存放在不同的区域,在main中调用swap函数的时候,会将main中的x,y的值赋给swap中的x,y。当swap函数中对x,y交换时只是对swap帧中的x,y做交换,并不会改变main中的x,y。所以当函数返回时main中的x,y并不会改变。swap执行过程图如下:
这里写图片描述

对于基本数据类型 short int long float double char byte boolean这八种按值传递调用函数并不会改变在原函数中的值。

引用数据类型的按值传递

引用数据数据类型分为三种:①接口 ②类 ③数组对于引用数据类型的按值传递先给出一个实例对比实例进行分析。

例2

public static void main(String[] args) {    int []a={10,20};System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=10,a[1]=20;      swap(a, 0, 1);System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;  }
public static void swap(int []a,int i,int j){int temp=a[i];a[i]=a[j];a[j]=temp;System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;}
//输出
/*a[0]=10 a[1]=20a[0]=20 a[1]=10a[0]=20 a[1]=10   
*/

运行程序后发现,swap函数对a[0] ,a[1]的操作竟然影响到了main函数中的a[0] ,a[1]的值,真是不可思议。为什么会产生如此之结果。原来引用类型的按值传递,传递的是对象的地址。还是用图来解释一下。

这里写图片描述
由图可以看出在swap中仅仅是得到了数组的地址,并没有对数组的元素进行复制,在swap中对数组的操作是直接对main函数中数组的操作,因此swap函数返回后main函数中的a[0] ,a[1]的值发生交换。

数组、类、接口按值传递的时候都是传递对象的地址。再来看一个比较复杂的实例。

例3

public class Main{public static void main(String[] args){Foo f = new Foo("f");changeReference(f); // It won't change the reference!modifyReference(f); // It will modify the object that the reference variable "f" refers to!}public static void changeReference(Foo a){Foo b = new Foo("b");a = b;}public static void modifyReference(Foo c){c.setAttribute("c");}
}

①Foo f = new Foo(“f”);
这里写图片描述

②public static void changeReference(Foo a)
这里写图片描述

③changeReference(f);
这里写图片描述

④Foo b = new Foo(“b”);
enter image description here
⑤a = b
enter image description here

enter image description here
⑥c.setAttribute(“c”);

enter image description here

经典笔试题目

试题1

public class Demo {public static void main(String[] args) {//demo1String str=new String("hello");char []chs={'w','o','r','l','d'};change(str, chs);System.out.println(str+" "+new String(chs));//-------------------------------------------------//demo2StringBuffer sb=new StringBuffer("hello");change(sb);System.out.println(sb);}public static void change(StringBuffer sb){sb.append(" world");
//      sb.deleteCharAt(0);}public static void change(String str,char[]chs){str.replace('h', 'H');chs[0]='W';     }       
}

上面程序段demo1和demo2分别输出什么,这里涉及到String特性,这道题目会做了,Java按值传递和按引用传递就彻底懂了,答案和解析先匿了。

试题2

public class foo {public static void main(String sgf[]) {StringBuffer a=new StringBuffer(“A”);StringBuffer b=new StringBuffer(“B”);operate(a,b);System.out.println(a+”.”+b);}static void operate(StringBuffer x,StringBuffer y) {x.append(y);y=x;}
}

参考文献

1.https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

这篇关于深入理解--Java按值传递和按引用传递的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134675

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有