【知识点】Java的值传递——为什么对象在函数里修改了,返回后未修改

2023-10-27

问题背景:

今天做题,遇到一个代码判断题,结果一直做错。
题目如下:

public class Point{
	private int x;
	private int y;
	public Point(int x, int y){
		this.x = x;
		this.y = y;
	}
	public void setLocaton(int  x,int y){
		this.x = x;
		this.y = y;
	}
	public static void main(String[] args){
		Point p1 = new Point(0,0);
		Point p2 = new Point(0,0);
		modifyPoint(p1,p2);
		System.out.println(p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
	}
	private static void modifyPoint(Point p1, Point p2){
		Point tempPoint = p1;
		p1 = p2;
		p2 = tempPoint;
		p1.setLocaton(5,5);
		p2 = new Point(5,5);
	}	
}

最终输出结果是什么:

 A. [0,0], [0,0]
 B. [5,5], [0,0]
 C. [0,0], [5,5]
 D. [5,5], [5,5]

正确答案是 B [ 0 , 0 ] , [ 5 , 5 ] B [0,0],[5,5] B[0,0],[5,5]
我百思不得其解,因为我认为modifyPoint(Point p1, Point p2)p1设置为[5,5], p2新建且初始化为[5,5],应该输出D选项。

在查询过程中,发现值传递和引用传递的说法:

  • 值传递: 就是复制,把数据传过去, 形参, 函数内操作不改变原来的变量
  • 引用传递:类似指针,传的地址, 要改变操作一起改变。

并且还有JAVA只有值传递的说法, 我一开始也没懂,直到把对象的内存地址打印出来才明白。

建议使用这个自己跑一下,体会下菜鸟JAVA在线编程环境

public class Point{
	private int x;
	private int y;
	public Point(int x, int y){
		this.x = x;
		this.y = y;
	}
	public void setLocaton(int  x,int y){
		this.x = x;
		this.y = y;
	}
	public static void main(String[] args){
		Point p1 = new Point(0,0);
		Point p2 = new Point(0,0);
        
        System.out.println("p1 内存地址="+System.identityHashCode(p1));
        System.out.println("p2 内存地址="+System.identityHashCode(p2));

		System.out.println("1>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		modifyPoint(p1,p2);
		System.out.println("函数后 p1 内存地址="+System.identityHashCode(p1));
        System.out.println("函数后 p2 内存地址="+System.identityHashCode(p2));
		
		System.out.println("7>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		System.out.println("------->"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
	}
	private static void modifyPoint(Point p1, Point p2){
        System.out.println("函数内 p1 内存地址="+System.identityHashCode(p1));
        System.out.println("函数内 p2 内存地址="+System.identityHashCode(p2));

		Point tempPoint = p1;
        System.out.println(
        "函数内 temp 内存地址="+System.identityHashCode(tempPoint));
		System.out.println("2>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		p1 = p2;
		System.out.println(
		"p1=p2操作,  p1 内存地址="+System.identityHashCode(p1));
		System.out.println("3>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		p2 = tempPoint;
		System.out.println(
		"p2=temp操作, p2 内存地址="+System.identityHashCode(p2));
		System.out.println("4>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		p1.setLocaton(5,5);
		System.out.println(
		"p1.set操作, p1 内存地址="+System.identityHashCode(p1));
		System.out.println("5>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
		p2 = new Point(5,5);
		System.out.println(
		"p2 = new 操作,  p2 内存地址="+System.identityHashCode(p2));
		System.out.println("6>>>"+p1.x+" "+p1.y+";;"+p2.x+" "+p2.y);
	}
	
}

输出结果为:

p1 内存地址=225534817
p2 内存地址=640070680
1>>>0 0;;0 0
函数内 p1 内存地址=225534817
函数内 p2 内存地址=640070680
函数内 temp 内存地址=225534817
2>>>0 0;;0 0
p1=p2操作,  p1 内存地址=640070680
3>>>0 0;;0 0
p2=temp操作, p2 内存地址=225534817
4>>>0 0;;0 0
p1.set操作, p1 内存地址=640070680
5>>>5 5;;0 0
p2 = new 操作,  p2 内存地址=1421795058
6>>>5 5;;5 5
函数后 p1 内存地址=225534817
函数后 p2 内存地址=640070680
7>>>0 0;;5 5
------->0 0;;5 5

关键看着几步:

2>>>0 0;;0 0
p1=p2操作,  p1 内存地址=640070680  !!这里p1指向了原来p2指向的内存地址
3>>>0 0;;0 0
p2=temp操作, p2 内存地址=225534817  !!p2指向了temp指向的内存地址
4>>>0 0;;0 0
p1.set操作, p1 内存地址=640070680    
5>>>5 5;;0 0    
p2 = new 操作,  p2 内存地址=1421795058 !!新内存地址
6>>>5 5;;5 5

然而由于值传递,函数外的对象指针,内存地址并没有变:

函数后 p1 内存地址=225534817
函数后 p2 内存地址=640070680
7>>>0 0;;5 5

所以输出结果的时候,正好是【0,0】,【5,5】

在这里插入图片描述

总结:

JAVA 函数 对象,传的是地址, 交换的也是地址,做好这个对应就行。(我居然蠢到打印了内存地址,才反应过来)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【知识点】Java的值传递——为什么对象在函数里修改了,返回后未修改 的相关文章

  • Java Swing:从 JOptionPane 获取文本值

    我想创建一个用于 POS 系统的新窗口 用户输入的是客户拥有的金额 并且窗口必须显示兑换金额 我是新来的JOptionPane功能 我一直在使用JAVAFX并且它是不同的 这是我的代码 public static void main Str
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • 从 127.0.0.1 到 2130706433,然后再返回

    使用标准 Java 库 从 IPV4 地址的点分字符串表示形式获取的最快方法是什么 127 0 0 1 到等效的整数表示 2130706433 相应地 反转所述操作的最快方法是什么 从整数开始2130706433到字符串表示形式 127 0
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • Google App Engine 如何预编译 Java?

    App Engine 对应用程序的 Java 字节码使用 预编译 过程 以增强应用程序在 Java 运行时环境中的性能 预编译代码的功能与原始字节码相同 有没有详细的信息这是做什么的 我在一个中找到了这个谷歌群组消息 http groups
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • 初始操作系统(Operation System)

    目录 操作系统的概念和功能 操作系统的四大特征 操作系统给发展过程 操作系统的运行机制 操作系统的概念和功能 操作系统这个词语对我们既熟悉又陌生 生活中会接触到 但具体的实现我么不从得知 生活中直接接触的操作系统有 windows linu
  • hadoop 常用缺少包错误

    package wc import java io IOException import java util StringTokenizer import org apache hadoop conf Configuration impor
  • 说说你对 Object.defineProperty 的理解?

    说说你对 Object defineProperty 的理解 什么是 为什么能实现响应式 小结 什么是 Object defineProperty 方法会直接在一个对象上定义一个新属性 或者修改一个对象的现有属性 并返回此对象 为什么能实现
  • printf输出%f %lld区别

    https blog csdn net u011497904 article details 42454483 utm source blogxgwz2
  • shell中的for循环示例

    1 利用for循环打印 示例代码 bin bash for i 0 i lt 3 i do for j 0 j lt 5 j 每行打印5个 打印三行 do echo n done echo done 2 利用for循环计算1到100的和 示
  • python读取xlsx格式的excle

    python读取excle的xlsx和xls格式代码略有不同 import pandas as pd from pandas import DataFrame if name main 读取excle表中的数据 file path r D
  • 【华为OD机试】数字反转打印【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 小华是个很有对数字很敏感的小朋友 他觉得数字的不同排列方式有特殊美感 某天 小华突发奇想 如果数字多行排列 第一行1个数 第二行2个 第三行3个 即第n行有n个数字
  • Java高级开发必知必会——反射

    title Java高级开发必知必会 反射 author rocklei123 tags Java 反射 categories Java date 2018 09 16 08 20 57 1 目标与意义 反射是Java开发中一个非常重要的概
  • Linux 之 shell 比较运算符

    运算符 描述 示例 文件比较运算符 e filename 如果 filename 存在 则为真 e var log syslog d filename 如果 filename 为目录 则为真 d tmp mydir f filename 如
  • 日期子组件

    日期子组件 如图
  • MySQL忘记密码的处理方法(MySQL重置密码)

    1 关闭正在运行的MySQL服务 在任务管理器中找到MySQL对应的服务 然后将其停止 2 打开CMD命令行窗口 转到mysql bin目录 3 输入mysqld skip grant tables 回车 mysqld skip grant
  • 《Collaborative Filtering for Implicit...》论文阅读

    论文题目 Collaborative Filtering for Implicit Feedback Datasets 链接 link 1 Introduction 随着电商的快速发展 为用户提供商品的排序很重要 推荐系统就是为用户提供符合
  • Spring Cloud微服务:Loadbalancer 实战

    nacos维护一个列表 但是我们请求服务不可能一个服务所有的都请求一遍 比如我做一笔转账 我找到其中一个做一次转账就够了 而不是看到有多个转账服务 都去转一次 那这个就需要 选择 选择这个靠谁来做呢 其实就是客户端负载均衡组件 Spring
  • git命令添加多个仓库,同步各分支代码,删除仓库、分支

    某些开发场景中 可能会遇到一套代码提交到2套git仓库 此时如何添加一个新仓库呢 假设已有仓库origin 想行添加一个仓库地址 命名为origin test与原仓库区分 1 查看现有仓库名及仓库地址 git remote v 2 添加新远
  • Pandsa时间序列采样频率滑窗及重采样

    目录 Pandas时间序列采样频率滑窗 1 滑窗函数rolling 获取近7天的销售总量 2 shift 及 diff 重采样 resample pandas时间戳及时间差 pandas日期处理DT对象 Pandas时间序列采样频率滑窗 1
  • 提高「程序员」的思维方式

    大家好 我是Tom哥 人和动物的最大区别就是 人具有思维能力 能将大脑里的东西实现出来 而动物则更多停留在模仿阶段 如 鹦鹉学舌 当然 这也是一种进化能力 这里着重提到了思维能力 人与人的思维能力也是有差异的 比如 一线程序员关心的这个项目
  • Oracle RAC failover 测试(连接时故障转移)

    Oracle RAC 集群最突出的表现就是高可用性 这些内容主要包括load balance以及failover 通过这些技术使得单点故障不影响客户端端应用程序对数据库的正常访问 以及通过创建service实现节点间负载均衡 本文主要描述O
  • Node.js 安装第三方模块

    所有的第三方模块包 下载安装的模块 使用的方式都是一样的 此文件以uuid举例 NPM的全称是Node Package Manager 是node的包管理器 是全球最大的开源生态系统 作用就是管理模块包 node模块包可以理解为工具 插件
  • Git常用命令cherry-pick

    Git常用命令cherry pick 将指定的提交应用于其他分支 可以用于恢复不小心撤销 revert reset 的提交 对于多分支的代码库 将代码从一个分支转移到另一个分支是常见需求 这时分两种情况 一种情况是 你需要另一个分支的所有代
  • 【知识点】Java的值传递——为什么对象在函数里修改了,返回后未修改

    问题背景 今天做题 遇到一个代码判断题 结果一直做错 题目如下 public class Point private int x private int y public Point int x int y this x x this y