当前位置: 首页 > news >正文

Stackoverflow问答:Java是传值还是传引用?

原文地址 译者:叶文海(yewenhai@gmail.com)
译者注:这是一篇在Stackoverflow上面的一个经典问题,也是Java开发者容易混淆的一个问题,我节选了其中两个vote最高的回复进行翻译。
问题:我一直认为Java的参数是按引用传递,然而我看过一些文章里说Java的参数并不是按引用传递的,比如这篇,这让我很迷惑。Java中的参数到底是按引用传递还是按值传递?

回答1:

在Java里参数是按值来传递的。比较难理解的可能是Java传递的是对象的引用,但这些引用是按值传递。
比如:


public static void main( String[] args ){
    Dog aDog = new Dog("Max");
    foo(aDog);
    if( aDog.getName().equals("Max") ){ //true
        System.out.println( "Java passes by value." );
    }else if( aDog.getName().equals("Fifi") ){
        System.out.println( "Java passes by reference." );
    }
}
public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}


在这个例子里面,执行完foo()方法之后,在main方法里再调用aDog.getName()方法依然会返回”Max”,在main方法中的
aDog并没有因为foo()的执行而被重写,这说明了参数是按值来进行传递的。如果是按照引用来传递的话在执行完foo()
方法之后aDog.getName()将会返回”Fifi”。
就像这样:


Dog aDog = new Dog("Max");
foo(aDog);
aDog.getName().equals("Fifi"); // true

public void foo(Dog d) {
    d.getName().equals("Max"); // true
    d.setName("Fifi");
}


回答2:

我刚刚发现你引用了我的文章 (译者注:这位是提问者引用文章的作者)
在Java的规范里说明了在Java中一切参数都是按值传递的,根本就没有引用传递这一说。
理解这个概念的关键是要明白


Dog myDog;


这里声明的并不是一个Dog对象,而是一个指向Dog对象的指针。
这是什么意思呢,就是当你执行


Dog myDog = new Dog("Rover");
foo(myDog);


本质上是你把创建好的Dog对象的地址传递给foo方法。(我说的‘本质上’其实是因为Java中的指针并不是直接的地址,不过可以简单的理解成这样)。
假设Dog对象在内存中的地址是42。那我们就是把42这个值传递给了foo方法。
如果foo方法的定义如下:


public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}


让我们来看看执行的时候会发生些什么。
1. someDog的值设置为42。
2. 在AAA行
      a.someDog指向一个内存地址为42的Dog对象。
      b.把Dog(内存地址为42)对象的name属性改为Max。
3. 在BBB行
      a.一个新的Dog对象被创建,我们假设它的内存地址是74。
      b.把这个74的内存地址值赋给someDog。
4. 在CCC行
      a.someDog指向一个内存地址为74的Dog对象。
      b.把Dog(内存地址为74)对象的name属性改为Rowlf。
5. 方法执行完毕。
现在让我们来想想在这个方法外面发生了什么:
myDog改变了吗?
这个问题的关键在于:
要明确myDog是一个指针,而不是一个实际的Dog对象。所以答案是它没有改变,myDog的值还是42;它指向的还是最开始的那个Dog对象(虽然在foo方法中的AAA行把它指向对象的name属性改成了Max,但是它指向的还是那个最初的Dog对象)。
这验证了改变所指对象的属性,但没有改变其指向。
Java的运行机制跟C很像。你可以给一个指针赋值,然后把这个指针传递给一个方法,之后在这个方法中你可以改变这个指针指向对象的数据,但是你不能改变这个指针的指向。

在C++,Ada,Pascal以及其他支持引用传递的语言中你可以直接改变传递的参数。如果Java是引用传递的话,那么在执行上面定义的foo方法的BBB行的时候someDog的指向就会被改变。
可以把引用参数当成被传递参数的别名,当这个别名被赋值的时候就相当于被传递的参数被赋值。
这对你有帮助吗?(我会把这个回答补充到我的文章里面去)。

相关文章:

  • 华中科大提出EAT-NAS方法:提升大规模神经模型搜索速度
  • opencv 人脸识别 (一)训练样本的处理
  • 俄罗斯食品来中国“过年”
  • Python入门基础
  • 虚拟现实与大数据
  • 市场监管总局:保健食品应标注不具疾病预防治疗功能
  • Linux进程管理之“四大名捕”
  • 甘肃崆峒古镇“文化赶集”:非遗“上台”贺新春
  • [共享WIFI]将笔记本网络设置为共享WIFI
  • python之logging模块
  • MySQL创建用户与授权
  • 中国PPP管理库项目累计投资额13.2万亿元
  • 三亚:严查“先登记支付房款、后补交社保或个税”行为
  • nginx+nagios在ubuntu下搭建过程全程指导
  • 2019年2月
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Git 使用集
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaScript实现分页效果
  • LeetCode18.四数之和 JavaScript
  • MaxCompute访问TableStore(OTS) 数据
  • mysql常用命令汇总
  • session共享问题解决方案
  • vue自定义指令实现v-tap插件
  • 给新手的新浪微博 SDK 集成教程【一】
  • 基于web的全景—— Pannellum小试
  • 讲清楚之javascript作用域
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • postgresql行列转换函数
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • # Panda3d 碰撞检测系统介绍
  • # 透过事物看本质的能力怎么培养?
  • #etcd#安装时出错
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • $.ajax()方法详解
  • (06)金属布线——为半导体注入生命的连接
  • (Java)【深基9.例1】选举学生会
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (二)hibernate配置管理
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (三)Honghu Cloud云架构一定时调度平台
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (转)编辑寄语:因为爱心,所以美丽
  • *2 echo、printf、mkdir命令的应用
  • .aanva
  • .NET CORE 第一节 创建基本的 asp.net core
  • .NET 回调、接口回调、 委托
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET文档生成工具ADB使用图文教程