Java浅解 值传递和引用传递

2024-06-18 21:38
文章标签 java 引用 传递 浅解

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

在上一篇文章对象中,略微提出了一些值传递和引用传递的概念,感觉需要写出篇简单的理解一下。

首先声明一点,java的传递时值传递,而非引用传递(即指针)。

  • 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
  • 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。是C语言的一种传递方式。

如何体现是值传递,代码如下:

public class Test{public static void main(String[] args) {int a=10;//静态变量System.out.println(a);updata(a);System.out.println(a);}public static void updata(int a) {a=a+10;System.out.println("updata中a的值   "+a);}}
//输出结果
10
updata中a的值   20
10

可见在updata 中对a进行多了修改,但是没有实际的参数值a进行修改,而a的值只能在方法体内生效,也就是局部变量。

我们这里也就简单的拓展一下局内变量和全局变量。

  • 局部变量:也称内部变量,是指在一个函数内部或复合语句内部定义的变量。

    简单的看,就是在方法体内生效,在之外是不会生效的变量。

  • 成员变量(全局变量):就是在方法体之外的变量。

java 变量取值,会就近原则,就是方法体内部有就不会去外部寻找如何理解:

注意: 此处的的a会全局变量

public class Test{static int a=10;//全局变量public static void main(String[] args) {System.out.println(a);updata(a);System.out.println(a);}public static void updata(int a) {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
10
updata中a的值   20
10

这样看程序运行似乎,虽然变成了全局变量,但是具体结果和局部变量没有什么区别。

请看下面代码:

public class Test{static int a=10;public static void main(String[] args) {System.out.println(a);updata();System.out.println(a);}public static void updata() {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
10
updata中a的值20
20

看见结果变了,难道就不知值传递了吗?

不,还是值传递,但是在updata 方法中没有形参 int a,所以也就没有所谓参数传递。而其运行规则我们说过,就近原则,所以局部没有,那么就需要找外面的的,而updata 中的a也就是全局变量a。所以此处不是引用传递,而是两个变量作用域不同而结果不同而已。

我们区别了全局变量和局内变量,现在我们回来继续说java中的值传递,想要理解这个,就必须对于java的堆和栈进一步理解。

java内存中分三个区:堆,栈,方法区。

  • 堆:分配的是对象的存储空间,也就是new之后真正数据存在的内存空间。其中可以理解比如new Dog,而dog就会存储在堆当中,而其就是一个大房子,而其毛色 color,公母 sex 等属性就其里面的房间信息。

  • 栈:基本数据类型以及对象的引用的地址

  • 方法区:就是类运行的时候加载类的信息以及static修饰的变量。

    • 加载类的信息:
      1. 这个类型的完整有效名。
      2. 这个类的直接父类的有效名,当然接口和object是除外,两者无父类
      3. 以及类的类型修饰符 public abstract等
    • 方法信息:就是防护的修饰符,以及方法类型,方法的参数和类型等,方法有关信息
    • static修饰的模块,以及修饰的变量

    方法区包含以上,以及其他的域信息,方法表(提高运算是一种数据结构)等

现在有疑问了,不是说java是值传递吗?为什么栈的定义提到了引用。

java的参数传递的时候是值传递,而其java中也没有如同C语言中指针的概念(也就是引用),但是不代表其没有使用指针。

在这里插入图片描述

可以简单理解如上图所示的一个结构。

int num=10;
String str="apple";

因为int是基本数据类型,所以直接存储在栈中,而string是类,所以在栈中存放的是堆的地址。

在这里插入图片描述

看到上面结构,有的就了一个大胆的想法,那就是,如果用string 类型的话,是否在局部修改的时候会影响实际参数呢?不解释,先看代码:

public class Test{public static void main(String[] args) {String a="test";System.out.println(a);updata(a);System.out.println(a);}public static void updata(String a) {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
test
updata中a的值test10
test

实参完全没有修改,不是说string是引用吗?为什么改变了而其实参没有改变。

在这里插入图片描述

其实这个就是在传递的时候形参复制了实参引用,但是string,本身尤其自己的特点,以为string 本身在建立后是不可改变的,但是所以虽然是通过+ 号进行了一个字符串添加,但是其意思就是新建了string对象,而其索引也就会变。

而如果需要string类型本身改变,因为大量使用string+会造成资源浪费,而java gc(垃圾回收)机制是jvm自己安排的。而是新建字符串,那就需要其衍生的两个类 StringBuffer和StringBuilder。这两个有append的方法可以在其对象上添加数据。

  1. StringBuilder 适用于单线程,其速度快但是不够安全。
  2. StringBuffer 适用于多线程,其速度慢但安全

现在我们看一下对象使用的引用,同样首先看代码

public class Dog {String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}public class Test{public static void main(String[] args) {Dog dog = new Dog();dog.setName("旺财")   System.out.println(dog.getName());updata(dog);System.out.println(dog.getName());}public static void updata(Dog dog) {dog.setName("元宝")System.out.println("updata中的值"+dog.getName());}}
//输出的值
旺财
updata中的值元宝
元宝

在这里插入图片描述

同理,也是传递了所在堆的地址,但是其没有新建一个dog对象,等于还是在原有的对象上调用了setName对dog进行赋值,所以本质还是值传递,而是引用一直没有说,但是一直存在。

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



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

相关文章

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

javacv依赖太大导致jar包也大的解决办法

《javacv依赖太大导致jar包也大的解决办法》随着项目的复杂度和依赖关系的增加,打包后的JAR包可能会变得很大,:本文主要介绍javacv依赖太大导致jar包也大的解决办法,文中通过代码介绍的... 目录前言1.检查依赖2.更改依赖3.检查副依赖总结 前言最近在写项目时,用到了Javacv里的获取视频

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