Java中为什么只有值传递?

news2024/11/24 12:50:54

Java中为什么只有值传递?

对于对象参数而言,实际参数传递给形式参数的只是一个内存地址,让形式参数也指向实际参数所指向的地址,传递的值的内容是对象的引用。

为什么会是这样?让我慢慢为你讲解。

对于Java的传递类型,常见错误理解如下:

错误理解一:值传递和引用传递,区分的是传递内容;如何是值,就是值传递;如果是引用,就是引用传递;

错误理解二:Java是引用传递;

错误理解三:传递的参数如果是普通类型,那就是值传递;如果是对象,那就是引用传递。

我们都知道,Java中定义方法的时候是可以定义参数的,比如Java中的main方法,方法中的args就是参数。

public static void main(String[] args)

参数在程序语言中分为实际参数和形式参数。

实际参数由主调函数传入,被调函数接受由主调函数传入的参数(也称为形式参数)。

当我们在程序中调用一个有参函数时,会将实际参数传递给形式参数。这个传递过程分为:值传递和引用传递。

值传递:调用函数传递实际参数时,会将实际参数复制一份副本,将复制的副本传入形式参数,当函数对参数进行修改时,修改的只是副本参数,不会影响到实际参数。

引用传递:调用函数传递实际参数时,会将实际参数的地址传递到形式参数,当函数对参数进行修改时,会影响到实际参数。

值传递

引用传递

区别

创建副本传入传入

将对象地址传入

结果

函数中无法修改原始变量

函数中能够修改原始变量

在了解上述概念后,可以写一段代码验证一下,看看Java中到底是值传递?还是引用传递?

在pass方法中修改参数j的值,分别打印出main方法和pass方法中的j值,看看输出结果有什么变化;

最终结果是,pass方法中修改的j值,并没有影响到main方法中的j值。

在接着看如下代码:

在pass方法中修改User对象的值,看看输出结果值:

这次实参的值居然被改变了,根据上述引用传递的定义,实际参数被修改了,这不就是引用传递吗?

先不要着急下结论,在看一个参数类型为对象的参数传递:

输出结果

这又是怎么回事呢?同样传递了一个对象,实际参数却没有被修改,又变成了值传递了?

这里先说一下String类型,当对String类型做任何修改时,都会产生新的String,值也是会变的。

上述的三个例子,表现结果却不一样,这就导致初学者出现困惑,甚至很多高级程序员对值传递都会存在困惑。

再举一个比较形象的例子,在深入理解一下值传递和引用传递

你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。
你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。但是,不管上面哪种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。那你说你会不会受到影响?而我们在pass方法中,改变user对象的name属性的值的时候,不就是在“砸电视”么。你改变的不是那把钥匙,而是钥匙打开的房子。

在拿上面的一个例子进行举例,真正的改变参数,看看会发生什么变化?

输出结果

通过一张图,你就能理解整个过程发生了什么,然后在告诉你,Java中为什么只有值传递?

当在main方法中创建一个User对象时,编译器会在堆中开辟一块内存,保存对象中name和gender的值,然后对象hollis指向该内存的对象0X1234456,如上图所示。

在调用pass方法时,hollis作为实际参数传入到形式参数user,会一并将地址0X123456传递给user,使user也指向地址0X123456,如上图所示。

在pass方法中对参数user进行修改,即重新实例化user,此时user会重新开辟一块内存地址0X45678,使user指向该地址,后面对user的任何修改,都不会在改变地址0X123456中的值,如上图所示。

看到这里,你觉得上述示例是什么传递方式?那肯定不是引用传递,如果是引用传递,肯定会修改实际参数的值,而实际上并没有修改实际参数的值。

这时你在返回去理解一下值传递和引用传递的概念,你就会发现上述的例子实际上是将实际参数的地址传递给了形式参数。

所以上面的传递方式是值传递,并非引用传递,把实际参数的地址当作值传递给形式参数。

在来回顾下这个例子:

看看这个例子中的传递过程发生了哪些变化?

在参数传递过程中,只是把实际参数的地址0X123456传递给了形式参数,方法中没有对形参本身进行修改,而只是修改形参指向地址中的值。

所以,值传递和引用传递的区别并不是在于传递的内容,而是实参到底有没有被复制一份给形参。

在判断实参内容有没有受到影响的时候,要看传递的内容是什么?如果你传递的是地址,就要注意这个地址的变化会不会有影响,而不是看地址指向对象的变化。

讲到这里,我们在反过头来看看String对象,同样都是传递对象,为什么String和User的表现结果不一样呢?

在pass方法中使用name = "hollischuang"试着去更改实际参数name的值,结果直接改变了name的引用地址。

这是因为name = "hollischuang"这段代码,会new一个String对象,再让name指向这个新的地址,等价于下面这段代码:

name = new String("hollischuang");

而实参name还是指向“Hollis”字符串所在的地址,当pass中修改name对象时,并不会修改到实际参数name的值。

所以,这就是为什么Java中只有值传递?只不过对于对象参数,值的内容是对象的引用。

总结

无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递(call by sharing)。其实Java中的参数传递严格意义上说应该是按共享传递。

按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。

在函数内部对参数进行操作时,需要先拷贝出地址,寻找到具体的值,再进行操作。如果该值在栈中,因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。

如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝,所以函数内对值的操作对外部变量是可见的。

简单点说,Java中的传递,是值传递,而这个值,实际上是对象的引用。

而按共享传递其实只是按值传递的一个特例罢了。所以我们可以说Java的传递是按共享传递,或者说Java中的传递是值传递。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1522498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自定义协议

应用层 有许多现成的协议(HTTP协议做网站必备),也有许多需要程序员自定义的协议. 1.自定义协议 自定义协议: 1.明确传递的信息是什么 2.约定好信息按照什么样的格式来组织成二进制字符串 举个例子: 当我们点外卖时,打开软件,会显示商家列表,列表中有很多项,每一项都包含了一…

波奇学Linux:线程安全和自选锁和读写锁

STL不是线程安全的 单例模式的线程安全 自选锁:当线程申请锁失败时,不是挂起,而是一直申请 挂起等待锁 :当线程申请锁失败时,把锁挂起 一般临界区时间短的适合自选锁,长的适合挂起等待锁

前后端分离:现代Web开发的协作模式

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

android中单例模式为什么会引起内存泄漏?

单例模式使用不恰当会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长, 如果一个对象已经不需要使用了,但是单例对象还持有该对象的引用,那么这个对象就不能被正常回收,因此会导致内存泄漏。 举个例子…

MySQL语法分类 DDL(1)

DDL(1)(操作数据库、表) 数据库操作(CRUD) C(Create):创建 //指定字符集创建 create database db_1 character set utf8;//避免重复创建数据库报错可以用一下命令 create database if not exists db_1 character set utf8;R(Retrieve):查询 //查询所…

PostMan测试文件上传

后端代码 package com.example.backend.controller;import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.example.backend.common.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org…

19. UE5 RPG使用GameplayEffect的Attribute Based Modifiers

前几篇文章我也说了GE的基础使用,但是,对一些属性的应用没有述说,后续,我将一点一点的将它们如何使用书写下来。 这一篇,主要就讲解一下Attribute Based Modifiers使用,先说一下它的应用场景,一…

使用Laravel安装器创建项目

使用Laravel安装器创建项目,使用Laravel安装器创建前先确保你的机器上已经下载了Laravel安装程序,可以通过终端界面查询是否下载了Laravel安装器,在终端中输入Laravel 查询,如下图所示则已下载Laravel安装程序,&#x…

macOS系统中通过brew安装MongoDB

Macos 修改目录权限: sudo chmod -R 777 你的文件夹 本文使用homebrew进行安装简单,因为从官网下载安装包并手动安装需要移动安装包到合适的目录下并配置环境变量等一大堆操作后才能使用数据库(若没有安装过brew请自行百度进行安装brew&am…

基于粒子群算法的分布式电源配电网重构优化matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1基本PSO算法原理 4.2配电网重构的目标函数 5.完整工程文件 1.课题概述 基于粒子群算法的分布式电源配电网重构优化。通过Matlab仿真,对比优化前后 1.节点的电压值 2.线路的损耗,这里计…

十四、自回归(AutoRegressive)和自编码(AutoEncoding)语言模型

参考自回归语言模型(AR)和自编码语言模型(AE) 1 自回归语言模型( AR) 自回归语言模型(AR)就是根据上文内容(或下文内容)预测下一个(或前一个&…

计算机网络(7)----应用层

目录 一.应用层的基本概念 1.应用层的基本概述 2.网络应用模型 (1)客户/服务器模型 (2)P2P模型 二.应用程序相关 1.DNS系统 (1)域名与域名服务器 (2)域名解析过程&#xff…

基于Java的无代码动态表单系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 动态类型模块2.2 动态文件模块2.3 动态字段模块2.4 动态值模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 动态类型表3.2.2 动态文件表3.2.3 动态字段表3.2.4 动态值表 四、系统展示五、核心代码5.1 查询档案类型5.…

农发行鱼台县支行组织开展3.15金融消费者权益保护教育宣传活动

为切实提升消费者金融素养及风险防范意识,3月15日农发行鱼台县支行组织开展以“金融消保在身边 保障权益防风险”为主题的“3.15”金融消费者权益保护教育宣传活动。 本次活动,该行重点围绕普及消费者八项基本权利、宣传金融纠纷多元化解机制、强化“三适当“原则、夯实诚信文…

sparksession对象简介

什么是sparksession对象 spark2.0之后,sparksession对象是spark编码的统一入口对象,通常我们在rdd编程时,需要SparkContext对象作为RDD编程入口,但sparksession对象既可以作为RDD编程对象入口,在sparkcore编程中可以通…

【LeetCode热题100】146. LRU 缓存(链表)

一.题目要求 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值&#xff0c…

RISC-V 编译环境搭建:riscv-gnu-toolchain 和 riscv-tools

RISC-V 编译环境搭建:riscv-gnu-toolchain 和 riscv-tools 编译环境搭建以及说明 操作系统:什么系统都可以 虚拟机:VMmare Workstation Pro 17.50.x (版本不限) 编译环境:Ubuntu 18.04.5 CPU:i7-8750h(虚拟机分配4核…

Vue+SpringBoot打造教学过程管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 教师端2.2 学生端2.3 微信小程序端2.3.1 教师功能如下2.3.2 学生功能如下 三、系统展示 四、核心代码4.1 查询签到4.2 签到4.3 查询任务4.4 查询课程4.5 生成课程成绩 六、免责说明 一、摘要 1.1 项目介绍 基于JAVAVu…

数据结构的概念大合集04(队列)

概念大合集04 1、队列1.1 队列的定义1.2队列的顺序存储1.2.1 顺序队1.2.2 顺序队的基本运算的基本思想1.2.3 顺序队的4要素的基本思想 1.3 环形队列1.3.1 环形队列的定义1.3.1 环形队列的实现 1.4 队列的链式存储1.4.1 链队1.4.2 链队的实现方式1.4.3 链队的4要素的基本思想 1.…

inux(CentOS)/Windows-C++ 云备份项目(项目文件操作工具类设计,完成项目基本文件操作-读写-压缩-目录操作)

文章目录 1. 项目文件操作工具类设计 1. 项目文件操作工具类设计 根据前面的分析,这个文件类的基本属性如下: 文件大小信息文件最后修改时间文件最后一次访问时间,方便文件的热点管理文件名称,需要从http 请求行上的uri中获取基…