为什么说 Java 是按值传递的?

  • 按值传递与按引用传递
  • Java 的按值传递
  • Java 的“传引用”
  • C++ 中的引用与指针
  • 总结

  很多人认为 Java 是按引用传递的。一方面,Java 有引用(reference)的概念。另一方面,可以通过函数形参修改函数外的某对象的字段,这看起来像是引用的特性。但实际上,Java 是按值传递的。这一点可以在官方及很多的权威书籍上得到印证,而且,Java 只有按值传递。

  如果对 Java 已经使用得非常熟练,对此理解不透彻也无伤大雅。不过很多行业最终都会要求专业性,对基本的概念分不清楚会降低威信力。那么,为什么说Java是按值传递的呢?

按值传递与按引用传递

  首先需要知道什么是按值传递(pass-by-value),什么是按引用传递(pass-by-reference)。无论是按值传递还是按引用传递,都是针对实参来说的。如果在传参过程中,形参得到的是实参的,那么就是按传递。如果得到的是实参的引用,那么就是按引用传递。

Java 的按值传递

  Java 的按值传递之所以令人疑惑是因为 Java 的变量语法。Java 中的非匿名变量有两种,一种是 基本类型变量、另一种是 对象引用变量。问题是 基本类型变量 的值直接是我们一般想要使用的数据,但 对象引用变量 不是这样,它储存的是某个匿名对象的引用。对象引用变量 的值 匿名对象的引用 不是我们直接需要的,我们直接需要的是这个匿名对象内部的数据——它的字段、它的方法等。注意,对象引用变量 的值和它引用的匿名对象内部的数据不是同一个概念。修改一个 对象引用变量 指向的匿名对象的字段,不等于修改这个 对象引用变量 的值。

  这个难以完全使用文字来描述清楚,笔者画了一个创建对象时的示意图如下。

  也就是说,在 Java 中,只能得到一个对象的引用,而得不到这个对象本身(但对于 基本类型,如果不考虑 Java 虚拟机的优化的话,在创建时的这个变量,就是这个变量本身。)。现在,让我们来看一个函数调用和传参的过程。

public class Main {class DemoClass {int demoField;public void setDemoField(int fieldValue) {this.demoField = fieldValue;}public int getDemoField() {return this.demoField;}}public static void demoFun(DemoClass formPara) {formPara = null;}public static void main(String[] args) {DemoClass demoObject = new DemoClass();demoObject.setDemoField(666);demoFun(demoObject); // 这会让 demoObject 的值变成 null 吗?// 这行代码会因“空引用”引发异常,还是输出 666 呢?System.out.println(demoObject.getDemoField());// TODO}
}

  请注意图中代码的注释,调用 demoFun(demoObject) 会让 demoObject 的值变成 null 吗?有经验的老手可能直接使用直觉判断出 demoObject 的值不会为 null ,尽管也许说不出原因。实际上,这就是按值传递的结果。通过函数调用 demoFun(demoObject),函数 demoFun 的形参 formPara 获得了实参 demoObject 的值,也就是匿名 DemoClass 对象的引用。因此,formPara 并不是 demoObject 的引用,所以修改不了 demoObject 的值,因此 demoObject 的值还为 null。也就是说,虽然 Java 有引用的概念,但不存在按引用传递。

  下面的这段代码也同样提醒了这一点。

public class Main {class DemoClass {int demoField;public void setDemoField(int fieldValue) {this.demoField = fieldValue;}public int getDemoField() {return this.demoField;}}public static void main(String[] args) {DemoClass demoObject = new DemoClass();demoObject.setDemoField(666);DemoClass otherReferVar = demoObject;otherReferVar = null; // 这会让 demoObject 的值变成 null 吗?// 这行代码会因“空引用”引发异常,还是输出 666 呢?System.out.println(demoObject.getDemoField());// TODO}
}

Java 的“传引用”

  还有一个在 Java 中流行使用的口语化词汇:传引用。由于此词汇广泛使用,因此这里不质疑它的合法性。那么,既然“传引用”是正确的,为什么前面又说 Java 是按值传递的呢?请注意,“传引用”中的“引用”与“按引用传递”中的“引用”指的不是同一个概念。在“传引用”中,只要中间有某个过程传递的是引用,就认为这是在“传引用”。比如,上面的函数调用 demoFun(demoObject) 中,函数 demoFun 的形参 formPara 获得了实参 demoObject 的值,也就是匿名DemoClass对象的引用。虽然此过程是传递的是实参 demoObject 的值(按值传递),但 demoObject 的值正好是匿名 DemoClass 对象的引用,因此此过程也可以称之为“传引用”。记住,在术语按值传递、引用传递中,衡量标准都严格要求是实参。而在 Java 中,永远也无法通过函数调用直接修改实参的值。

C++ 中的引用与指针

  虽然有引用的概念不代表函数调用时按引用传递,但不是什么编程语言的引用都只能按值传递的。比如 C++ 中的引用,可以按值传递,也可以按引用传递,这取决于定义调用函数的定义,而和实参是不是引用无关。而 JavaScript 中的引用和 Java 一样,只能按值传递。

  不过,在此处笔者还要纠正一下,C++ 中的引用与 Java 中的引用从性质上来说是不同的。Java 中的引用更像是 C++ 中的指针。也就是说,C++ 中的引用与 C++ 中的指针不是同一个性质的概念。有的“自认为喜欢钻研”的人喜欢吹捧自己的“独特见解”:C++ 中的引用在内部原理上可以由指针来实现,因此 C++ 中的引用与指针是一码事。这个观点算不上开阔。内部原理如何与概念是否相同无关。从设计模式来说,同一个问题可以由不同的设计模式来实现,不代表实现这个问题的所有的设计模式本质上都是相同的,更不代表这个问题就是一种设计模式,且与实现它的设计模式相同。C++ 的指针变量被赋值时,这个指针之前指向的对象不受影响,但 C++ 的引用就不同了。C++ 的引用变量在创建之后就几乎与其引用的对象完全相同。

  有的人认为 C++ 中的指针与 Java中的引用不同,理由是 C++ 的指针与 C++ 其它普通的类型的量纲不一致。确实如此。不过,这只是因为 C++ 中存在非匿名的对象。如果这类人对声明指针时使用的星号 * 非常敏感,C++ 中还提供了关键字 typedef。该关键字专门为有“整体”数学思想的人提供。如果拒绝使用非匿名的对象(只使用关键字 new 创建对象),且使用关键字 typedef 消除使用指针时必定使用的解引用运算符 *,这些人将会惊奇的自我发问:自己使用的究竟是哪门语言。

总结

(左值创建、右值创建指的是创建变量时位于赋值运算符 = 的左右还是右边)

  • Java:

    • 只能按值传递。

    • 对象都是匿名的。右值创建。创建对象时返回其引用。

    • 基本类型变量都是非匿名的。左值创建。匿名的基本类型都是常量。

  • JavaScript:同 Java。

  • C++:

    • 可按值传递,也可按引用传递。传递规则与目标是基本类型还是对象无关。

    • 变量和对象可匿名创建,也可不匿名创建。可左值创建,也可右值创建。创建匿名变量和对象时返回其指针值。

  • C:只能按值传递。无对象。其它同 C++。

为什么说 Java 是按值传递的?相关推荐

  1. Java:按值传递还是按引用传递详细解说

     Java:按值传递还是按引用传递详细解说 2012-11-14 23:02 44567人阅读 评论(17) 收藏 举报 本文章已收录于: 分类: java(48) 作者同类文章X 变量(6) 作 ...

  2. java值传递string_关于java:按值传递(StringBuilder与String)

    本问题已经有最佳答案,请猛点这里访问. 我不明白为什么system.out.println(name)在不受方法的concat函数影响的情况下输出sam,而system.out.println(nam ...

  3. Java是“按引用传递”还是“按值传递”?

    我一直认为Java是通过引用传递的 . 但是,我已经看到一些博客文章(例如this blog )声称不是. 我不认为我能理解他们的区别. 有什么解释? #1楼 Java始终按值传递参数,而不按引用传递 ...

  4. java中是值传递引用传递_Java是按值传递而不是按引用传递

    java中是值传递引用传递 One of the biggest confusion in Java programming language is whether java is Pass by V ...

  5. 传递字符串_一道经典面试题:字符串在Java中如何通过“引用”传递

    这是Java的一个经典问题. stackoverflow上也有很多类似的问题,有很多不正确/不完整的答案. 如果你想的不多,问题很简单. 但如果你多想想,可能会很困惑. 一.一个有趣且令人困惑的代码片 ...

  6. Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?

    来自:沉默王二 在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很 ...

  7. 10道棘手的Java面试题,看看你能答对几个?

    昨晚看了几个老外分享的面试题,还挺有意思的.下面我们分两期来一起看看都是些怎么样的问题难到了老外?如果是你,是否可以都答对呢? 如果您对原文感兴趣,也可以通过这个链接查看:https://levelu ...

  8. java与c语言工作量对比比例,对比平台-- C ++与Java之间的差异

    C ++与Java之间的差异 创建为C语言扩展的通用编程语言,可以称为带有类的C语言,称为C ++.该语言为系统和内存提供高级控制,并且随着跨平台语言开发高性能应用程序.该语言由Bjarne Stro ...

  9. java流的传递方式是_java中数据的传递方式到底是怎样的!

    今天早上我了一道有关java的题.主要考点是考java中值得传递方式. 之前我在javaoo里总结的是:基本数据类型中保存的是实际的值,引用数据类型保存的是被引用的内存地址,那么基本数据类型就是按值传 ...

最新文章

  1. 五大常用经典算法—回溯算法
  2. XTU 1252 Defense Tower
  3. 使用VSTS为ASP.NET Core构建DevOps CI/CD管道
  4. 新建3台linux7.5部署k8s,之后的软件安装全部都在k8s
  5. java对音频文件的频谱分析
  6. CSS从入门到精通——文本与字体样式
  7. 抖音c语言表白编码,抖音微信表白代码大全 微信表白代码总汇
  8. c语言fltk图形库,FLTK编程模型
  9. 荣耀手机环比倍增,小米有点受伤
  10. JS中的对象以及在web前端的应用
  11. JSP环境的搭建及程序初步
  12. BgSub 无需上传图片即可在线自动抠图的AI工具
  13. 毕设第三周(12月19日——12月25日)
  14. OpenSSL SSL_read: Connection was aborted, errno 10053的问题
  15. 楚留香服务器维护,【楚留香】4月20日维护公告
  16. 什么是百度信息流广告?
  17. 2023年技术积累方向---梳理
  18. 百格活动教你16种策略,从活动策划小白进阶为活动策划大神!
  19. 准备pmp考试第13天
  20. 操作系统学习笔记(三):多道程序的基础——空分复用

热门文章

  1. 细述:nginx http内核模块提供的变量和解释
  2. Spring Cloud Alibaba迁移指南(四):零代码兼容 Api-Gateway
  3. redis之sorted sets类型及操作
  4. Zabbix 3.2.6 升级到 Zabbix 3.4.3
  5. 黑客还是间谍?让你惊出一身冷汗的10个社会工程学黑客攻击手段
  6. (六)jQuery选择器
  7. 创维37K05HR黑屏有声音故障维修
  8. Salt Master外部Job Cache配置
  9. Nginx中gzip_static使用测试
  10. AutoConfigurationImportSelector是什么?