澄清:Java中只有按值传递,没有按引用传递!

  前言:在[url=http://www.iteye.com/topic/214374]JAVA面试题解惑系列(五)——传了值还是传了引用?[/url]中作者提到了“[color=red]JAVA中的传递都是值传递吗?有没有引用传递呢?[/color] ”这个问题,最终得到:
[quote]最后我们得出如下的结论:

1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。 [/quote]
  事实上有着这种想法的人为数不少。但这个结论不完全正确。正确的说法应该是:[color=red]在Java中,只有按值传递,没有按引用传递[/color]!

  简单说,这里其实就是一个关于什么是“按引用传递”的问题。
  如果你写了这样一个方法:

swap(Type arg1, Type arg2) {
Type temp = arg1;
arg1 = arg2;
arg2 = temp;
}


  并且像下面这样调用该方法:

Type var1 = ...;
Type var2 = ...;
swap(var1,var2);

  确实能调换var1与var2的值,才可能是“按引用传递”

  有关这个问题的进一步解释,我这儿不再赘述,只给出两篇不错的文章:
  ☆  [url=http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html]Does Java pass by reference or pass by value?[/url]
  ☆  [url=http://javadude.com/articles/passbyvalue.htm]Java is Pass-by-Value, Dammit![/url]

  下面是第二篇的全文,有空再翻译:

Introduction

I finally decided to write up a little something about Java's parameter passing. [color=red]I'm really tired of hearing folks (incorrectly) state "primitives are passed by value, objects are passed by reference"[/color].

I'm a compiler guy at heart. The terms "pass-by-value" semantics and "pass-by-reference" semantics have very precise definitions, and they're often horribly abused when folks talk about Java. I want to correct that... The following is how I'd describe these

[color=red]Pass-by-value[/color]
The actual parameter (or argument expression) is fully evaluated and the resulting value is copied into a location being used to hold the formal parameter's value during method/function execution. That location is typically a chunk of memory on the runtime stack for the application (which is how Java handles it), but other languages could choose parameter storage differently.
[color=red]Pass-by-reference[/color]
The formal parameter merely acts as an alias for the actual parameter. Anytime the method/function uses the formal parameter (for reading or writing), it is actually using the actual parameter.

[color=red]Java is strictly pass-by-value, exactly as in C[/color]. Read the Java Language Specification (JLS). It's spelled out, and it's correct. (See [url]http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#37472[/url])

In short: Java has pointers and is strictly pass-by-value. There's no funky rules. It's simple, clean, and clear. (Well, as clear as the evil C++-like syntax will allow ;)

Note: See the note at the end of this article for the semantics of remote method invocation (RMI). What is typically called "pass by reference" for remote objects is actually incredibly bad semantics.
The Litmus Test

There's a simple "litmus test" for whether a language supports pass-by-reference semantics:

Can you write a traditional swap(a,b) method/function in the language?

A traditional swap method or function takes two arguments and swaps them such that variables passed into the function are changed outside the function. Its basic structure looks like

// NON-JAVA!
swap(Type arg1, Type arg2) {
Type temp = arg1;
arg1 = arg2;
arg2 = temp;
}


If you can write such a method/function in your language such that calling

// NON-JAVA
Type var1 = ...;
Type var2 = ...;
swap(var1,var2);


actually switches the values of the variables var1 and var2, the language supports pass-by-reference semantics.

For example, in Pascal, you can write

{ Pascal }
procedure swap(var arg1, arg2: SomeType);
var
temp : SomeType;
begin
temp := arg1;
arg1 := arg2;
arg2 := temp;
end;


...
{ in some other procedure/function/program }
var
var1, var2 : SomeType;
begin
var1 := ...;
var2 := ...;
swap(var1, var2);
end;


or in C++ you could write

// C++
void swap(SomeType& arg1, Sometype& arg2) {
SomeType temp = arg1;
arg1 = arg2;
arg2 = temp;
}


...

SomeType var1 = ...;
SomeType var2 = ...;
swap(var1, var2); // swaps their values!



(Please let me know if my Pascal or C++ has lapsed and I've messed up the syntax...)

But you cannot do this in Java!
Now the details...

The problem we're facing here is statements like

In Java, Objects are passed by reference, and primitives are passed by value.

This is half incorrect. Everyone can easily agree that primitives are passed by value; there's no such thing in Java as a pointer/reference to a primitive.

However, Objects are not passed by reference. A correct statement would be Object references are passed by value.

This may seem like splitting hairs, bit it is far from it. There is a world of difference in meaning. The following examples should help make the distinction.

In Java, take the case of

  public void foo(Dog d) {
d = new Dog("Fifi");
}

Dog aDog = new Dog("Max");
foo(aDog);


the variable passed in (aDog) is not modified! After calling foo, aDog still points to the "Max" Dog!

Many people mistakenly think/state that something like

  public void foo(Dog d) { 
d.setName("Fifi");
}

shows that Java does in fact pass objects by reference.

The mistake they make is in the definition of

  Dog d;


itself. When you write

  Dog d;


you are defining a pointer to a Dog object, not a Dog object itself.

Calling

  foo(d);


passes the value of d to foo; it does not pass the object that d points to!

The value of the pointer being passed is similar to a memory address. Under the covers it's a tad different, but you can think of it in exactly the same way. The value uniquely identifies some object on the heap.

The use of the word "reference" in Java was an incredibly poor choice (in my not-so-humble opinion...) Java has pointers, plain and simple. The designers of Java wanted to try to make a distinction between C/C++ pointers and Java pointers, so they picked another term. Under the covers, pointers are implemented very differently in Java and C/C++, and Java protects the pointer values, disallowing operations such as pointer arithmetic and invalid runtime casting.

However, it makes no difference how pointers are implemented under the covers. You program with them exactly the same way in Java as you would in C or C++. The syntax is just slightly different.

In Java,

  Dog d;   // Java


is exactly like C or C++'s

  Dog *d;  // C++


And using

  d.setName("Fifi");  // Java


is exactly like C++'s

  d->setName("Fifi"); // C++


To sum up: Java has pointers, and the value of the pointer is passed in. There's no way to actually pass an object itself as a parameter. You can only pass a pointer to an object.

Keep in mind, when you call

  foo(d);


you're not passing an object; you're passing a pointer to the object.

For a slightly different (but still correct) take on this issue, please see http://www-106.ibm.com/developerworks/library/j-praxis/pr1.html. It's from Peter Haggar's excellent book, Practical Java.)


[color=red]A Note on Remote Method Invocation (RMI)[/color]

When passing parameters to remote methods, things get a bit more complex. First, we're (usually) dealing with passing data between two independent virtual machines, which might be on separate physical machines as well. Passing the value of a pointer wouldn't do any good, as the target virtual machine doesn't have access to the caller's heap.

You'll often hear "pass by value" and "pass by reference" used with respect to RMI. These terms have more of a "logical" meaning, and really aren't correct for the intended use.

Here's what is usually meant by these phrases with regard to RMI. Note that this is not proper usage of "pass by value" and "pass by reference" semantics:

RMI Pass-by-value
The actual parameter is serialized and passed using a network protocol to the target remote object. Serialization essentially "squeezes" the data out of an object/primitive. On the receiving end, that data is used to build a "clone" of the original object or primitive. Note that this process can be rather expensive if the actual parameters point to large objects (or large graphs of objects).
This isn't quite the right use of "pass-by-value"; I think it should really be called something like "pass-by-memento". (See "Design Patterns" by Gamma et al for a description of the Memento pattern).

RMI Pass-by-reference
The actual parameter, which is itself a remote object, is represented by a proxy. The proxy keeps track of where the actual parameter lives, and anytime the target method uses the formal parameter, another remote method invocation occurs to "call back" to the actual parameter. This can be useful if the actual parameter points to a large object (or graph of objects) and there are few call backs.
This isn't quite the right use of "pass-by-reference" (again, you cannot change the actual parameter itself). I think it should be called something like "pass-by-proxy". (Again, see "Design Patterns" for descriptions of the Proxy pattern).
CAD图纸智能搜索三大突破:图纸秒搜技术、相似度匹配与AI语义搜索 CAD图纸作为核心资产,长期面临管理难题:传统全文检索需逐张打开图纸人工查找,效率低下;相似图纸匹配依赖人工比对,误差率高;非专业人员难以通过模糊描述精准定位图纸。针对这些问题,唯杰地图推出三项智能解决方案:一是基于现代化索引引擎的​​全文搜索​​,支持秒级检索图纸内的文字、图层、块名称等,并可多条件组合查询;二是​​相似度搜索​​,通过SIFT算法和深度学习提取几何特征与拓扑结构,实现高精度匹配;三是​​AI语义搜索​​,利用大模型解析自然语言指令(如“查找半径为10的红色圆”),直接定位目标图形。 阅读详情

相关推荐

Qt开发者必看:QTimer::singleShot的5个实战避坑指南(含lambda和多线程案例)

本文为Qt开发者提供了QTimer::singleShot的5个关键实战避坑指南,涵盖lambda捕获、对象生命周期和多线程安全等核心难点。通过对比错误与正确代码示例,深入解析了如何避免悬空指针、确保线程执行上下文正确以及管理定时任务资源,帮助开发者编写更健壮、可靠的延迟执行代码。

stem5的博客 467

Java中只有按值传递,没有按引用传递!

今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?  我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这一特性很是熟悉! 结果发现,我错了! 答案是: 值传递!Java中只有按值传递,没有按引用传递!   回家后我就迫不及待地查询了这个问题,觉得自己对java这么基础的问题都搞错实在太...

guhanjie的专栏 609

Cortex-M异常处理深度解析:从HardFault到调试实战

在嵌入式开发中,Cortex-M系列处理器的异常处理机制是保障系统可靠性的核心。然而,面对HardFault、MemManage、BusFault等异常时,开发者往往陷入迷茫。本文结合SEGGER AN00016和Keil AN209两篇权威文档,深入剖析异常根源、寄存器解析及调试技巧,并通过代码实例演示如何快速定位问题。

汽车电子软件领域知识分享 2534

Java中只有值传递没有引用传递

当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。 在java中,新创建的实体对象在堆...

Crystalqy的博客 583

通俗傻瓜式理清光栅化渲染和光线追踪渲染的原理

用通俗语言傻瓜式的讲清楚光栅渲染和光线追踪渲染的原理,方便没有相关理论基础的朋友理解入门。

qq_37366618的博客 2万+

孤读paper——《GhostNet:More Features from Cheap Operations》

《GhostNet:More Features from Cheap Operations》   发现一个点并解决就是一篇CVPR,该文章主要发现了优秀的网络的特点是feature map提取过程中的冗余性,这种冗余性体现在很多成对的feature map间很像,就好像彼此的“ghost”,而这种特征冗余性对于理解图像来说还是必要的,所以文章把feature map分为两种,一种是本质特征,一...

雄关漫道真如铁 而今迈步从头越 5151

Java到底有没有引用传递?

(1)“在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。 (2)在Java里面只有基本类型和String,其它的都是按引用传递。

小疯的代码健身房 8796

GEE APP:时间序列影像批处理工具:按月筛选与智能导出解决方案出工具

本文介绍了一个基于Google Earth Engine(GEE)开发的智能时序影像处理工具,可高效处理遥感影像时间序列数据。该工具采用三栏式交互布局,包含控制面板、地图显示和缩略图预览区域。核心功能包括:1)灵活的时间筛选机制,支持年度范围选择和月份批量选择;2)智能影像筛选算法,基于云量、空间覆盖等条件自动选择最佳影像;3)交互式缩略图预览,支持点击加载完整影像;4)自动化批量导出系统,实现标准化命名和统一存储。工具可广泛应用于农业监测、城市扩张研究、生态环境评估等领域,显著提高遥感数据预处理效率,确保

此星光明博客 114

Java语言中没有引用传递,只有值传递。到底对不对?

在传递引用的时候其实是复制了一份引用传进去的. A a=new A(); test(a) 相当于 (A b=a; test(b) ) 如果传的是基本数据类型,修改这个值并不会影响作为参数传进来的那个变量,因为你修改的是方法的局部变量,是一个副本。  如果传的是一个对象的引用,也是一样的,也是一个副本,但是这个副本和作为参数传进来的那个引用指向的是内存中的同一个对象,所以你通

xin.wang的博客 1430

从零开始学习PX4源码0(固件下载及编译)

本节主要记录从零开始学习PX4源码1(固件下载)的过程,欢迎批评指正!!!下载固件主要分为两个版本,之前稳定版本和最新官网发布版本,为什么要下载两个版本,主要是说明两个版本有一定的差异(开发环境及源码文件格式等),我们是从之前版本开始学习,为什么不从最新的?因为之前版本代码文件格式还是固定的,最新的变化很大,不利于初学者学习,apm和px4不好的地方就是之前版本v1.7.2和最新版本v1.14.0有些文件总是在变化,这样很不好。

陌城烟雨 4616

阿波罗开发板硬件架构与STM32模块化设计详解

嵌入式开发板的模块化设计是提升硬件复用性、降低迭代成本的关键技术路径。其核心在于底板与核心板的电气解耦与功能分层,依托STM32系列MCU(如F429/F767)的丰富外设资源与引脚复用能力,实现信号完整性、电源域隔离与热管理的系统级协同。该架构显著支撑工业HMI、智能家居网关、便携医疗设备等典型场景,尤其在RGB LCD驱动、QSPI Flash内存映射、多协议通信(CAN/RS485/USB)及低功耗唤醒(WK_UP按键)等工程实践中展现出高可靠性与易调试性。本文围绕阿波罗开发板展开深度解析,覆盖最小系

weixin_42510201的博客 65

Java中的参数传递,到底是值传递还是引用传递?

Java中的参数传递,到底是值传递还是引用传递? 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。 错误理解二:Java是引用传递。 错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。

iqqcode 1万+

使用epiDisplay包中的logistic

其中的logistic.display函数可以用于获取逻辑回归模型的汇总统计信息,包括自变量的优势比和置信区间,以及回归系数的Wald检验的p值。最后,我们使用print函数打印出汇总统计信息。使用epiDisplay包中的logistic.display函数获取逻辑回归模型的汇总统计信息(包括自变量的初始和调整后的优势比及置信区间,回归系数的Wald检验的p值)- R语言。通过使用logistic.display函数,我们可以方便地获取逻辑回归模型的重要统计信息,并对自变量的影响进行解释和推断。

CyberJolt的博客 609

Java只有值传递,没有引用传递!

结论:Java中的参数传递,只有值传递,没有引用传递!

Yu_Mariam的博客 1611

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

终于明白了!java只有值传递,而没有引用传递

有人就又会疑问了,形参里的是对象,那传递的应该是引用本身,这肯定是引用传递,我确实这样疑惑过,但仔细想想,其实还是值传递,因为他们指向同一个堆,所以改变堆内内容当然对原本有影响了,我们所说的没有影响是栈中的原数据,这里是对象a,副本a根本对原实参a无法造成影响,因为a是对象,所以你对对象a中数据的更改跟a没有关系,因为堆中的数据时共享的,很多人都会理解错这一点。我们发现值传递和我们上面所说一致,它是把实参复制一份通过形参传给方法,而这个方法改变的只是副本,无法对原来的数值改变。"调用过程中a的值".....

HD243608836的博客 1879

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Java 中的按值传递

Java 中只有按值传递     "Java 中只有按值传递",初看到这几个字有点不敢相信,无数次通过函数改变过对象,无数次跟同事说 Java 在传对象的时候是按引用传递。后来细细想想,之所以以为 Java 传对象是按引用传递是因为其中有很多概念都没理清楚,与 C++ 中的搞混了。从 C++ 转 Java 的时候将 C++ 中的知识点映射到 Java 没错,这有利于 C++ 转 Java 的人更...

mengsofts的专栏 1304

Java中的参数传递,到底是值传递还是引用传递?(*)

参数传递

weixin_42408447的博客 5090

⑦Java中只有按值传递,没有按引用传递!

今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?  我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这一特性很是熟悉! 结果发现,我错了! 答案是: 值传递!Java中只有按值传递,没有按引用传递!   回家后我就迫不及待地查询了这个问题,觉得自己对j

ligengk的专栏 509

26. 值传递和引用传递的区别的什么?为什么说Java中只有值传递

Java 采用值传递机制,基本类型传递的是值的副本,对象传递的是引用副本。方法内修改基本类型不影响原值,但通过对象引用副本可修改对象状态(如属性更改)。Java 没有真正的引用传递,因为重新赋值对象引用不会影响外部变量。这种设计确保了数据安全,避免意外修改外部变量。即便对象参数表现出类似引用传递的行为,本质仍是传递引用的副本(值传递),符合 Java 安全、简单的设计哲学。

思你日度难眠 922

Java 值传递与引用传递

Java参数传递机制深度解析:只有值传递,没有引用传递 本文系统阐述了Java参数传递的核心机制,明确指出Java中只有值传递,不存在引用传递。对于基本类型,传递的是值的副本;对于引用类型,传递的是对象引用地址的副本。文章通过内存模型分析、20+代码实例和与其他语言的对比,揭示了以下关键点: 值传递的本质是传递副本,形参修改不影响实参 引用类型看似"引用传递"的表现,实则是通过地址副本修改共享对象 Java选择单一值传递机制是为了简化设计、确保安全 开发中需注意不可变对象、引用重新赋值等

果酱 の 博客 1572

integer是值传递还是引用传递_Java只有值传递

可能有很多小伙伴都知道Java是值传递,但是又说不出个所以然,我也是这样,于是去看了一些博客,下面来一个简单的总结。首先说结论:Java中只有值传递,没有引用传递。这里涉及到值传递和引用传递两种传递机制:值传递(pass by value):是指在调用方法(或者函数)时,将实际参数复制一份传递到方法(或者函数)中,这样在函数中如果对形式参数进行修改,将不...

weixin_39786534的博客 1329

为什么说Java中只有值传递,沒有引用传递

在开始深入讲解之前,有必要纠正一下大家以前的那些错误看法了。如果你有以下想法,那么你有必要好好阅读本文。 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。 错误理解二:Java是引用传递。 错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。 实参与形参 我们都知道,在Java中定义方...

qq_31207917的博客 621

Java为什么只有值传递

本文转载自公众号 Hollis 对于初学者来说,要想把这个问题回答正确,是比较难的。在第二天整理答案的时候,我发现我竟然无法通过简单的语言把这个事情描述的很容易理解,遗憾的是,我也没有在网上找到哪篇文章可以把这个事情讲解的通俗易懂。所以,就有了我写这篇文章的初衷。这篇文章中,我从什么是方法的实际参数和形式参数开始,给你讲解为什么说Java中只有值传递。 ​ 辟谣时间 关于这个问题,在StackOverflow上也引发过广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的

wss8752的博客 1015

学习Java——为什么java只有值传递

面对梦想道路上的困苦艰难坎坷,执着是最好的利刃,它会帮助一个人劈开艰难,穿越困境,抵达铺满鲜花的梦想。————《人民日报》

L170311的博客 1845

Java是值传递还是引用传递?还是两者皆有?

很多人不知道Java属于值传递还是引用传递,大多数可能认为Java传基本类型时是值传递,传对象时是引用传递,那么事实真是如此吗?

小夏陌的博客 4万+
上一篇: Euler Project解题汇总 031 ~ 040
下一篇: Project Euler解题汇总 041 ~ 050
JavaSxy
博客等级 码龄21年 1粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值