返回信息流当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
不理解了
这是一条镜像帖。来源:北邮人论坛 / java / #35202同步于 2014/10/12
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
为什么说java只有值传递?
HB0318
2014/10/12镜像同步15 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
有这个疑问是因为学Python,为啥同样的情况,Python叫引用传递,java就是值传递啦?求教大神。
【 在 taoch 的大作中提到: 】
: 其他还好
: “但对象的引用(不是引用的副本)是永远不会改变的”
: 这句我有点晕。。
知乎用多了,我用知乎式的长篇大论尝试解释一下。
估计lz是没学C系语言吧,有些人解释高级语言参数传递爱搞什么值传递、引用传递、地址传递来解释,本来是想降低理解学习难度,但实际却越搞越乱。
为什么会有参数传递?函数调用才产生的参数传递,函数调用时会发生入栈,所以首先得理解栈模型。函数参数会在函数调用时压入栈,如果你是语言设计者,你怎么把函数要用到的参数压入栈?
其实无非两种选择:1,直接按参数在内存中的内容复制一份压入到栈中;2,把存储参数所在的内存地址传进去,在函数中通过内存地址来找到它。内存地址也无非就是一个具体的数值,所以在传地址时也是相当于把一个具体的数值(代表着实际参数的地址)压入栈中。
http://img5.tuchuang.org/uploads/2014/10/传参示意图.png
一图胜千言,栈1、栈2表示的是两种传参的压栈方式。栈1压栈时直接把参数在内存中的内容复制压进去,黑线表示按内存内容复制。栈2中只有int i 按内存复制,对象o1、o2都只传了一个地址的值进去,蓝线表示传参时用参数的内存地址来传,比如0x00000001和0x00000008。很显然的是,在栈1中,如果修改对象o1、o2,原内存中的o1、o2对象是不会改变的,因为它们存在不同的内存空间中。但是在栈2里,修改o1、o2对象时,原内存中的对象会发生相应变化,因为它们指向相同的内存地址。但前提是你不能修改指向对象地址的变量的值,比如原本指向o1对象的地址变量o1_address = 0x00000001, 现在你令o1_address = 0x000000032,此时你再对o1_address所指向的对象做修改,是不会影响到原来内存中的o1对象的,因为你的地址值已经指向了内存中其它的对象。
入栈时无论你怎么传,其实都是把某些值压到栈中,所有有些人一直坚称:"无论什么语言传参都是值传递"。其实你如果理解了以上传参过程,叫传值还是传引用什么的根本不重要,关键在于理解传参压栈时压入的是什么。
对于java而言,压栈的方式被强行限定为上图的栈2模式,值类型直接复制内存,对象则把地址传进去。这样好处很明显,你即使不理解内存、栈知识还是能在不出错的情况下用对,所以这也是java好入门的一个原因。但对C系语言,你可以指定自己要传参的机制,比如你可以按栈1来传,也可以按栈2方式,也可以全部用地址传,把栈2中的int i 也用内存地址来传,甚至可以传两级指针或多级指针都行,这时候如果不理解传参内存模型就是灭顶之灾了。
为什么传个参要搞这么复杂?既然无论怎么传参都把具体的值压到栈中,那传参都搞成按栈1的内存复制不就得了,也不会有人搞混淆了。但这么做有两个很明显的缺点:
1. 效率低下,可以看到图中我特意把对象o1、o2大小画得比int i 大,就是想表达对象会占用更大的内存空间,如果复制内存内容时会耗用更多的时间和系统资源,而且很多时候没有必要。
2. 不便于在函数中修改多个传入参数对象,如果全部按内存复制传递,那只能通过函数返回值来把修改后的一个对象返回来,会使对象的传递和使用极其麻烦。
至于python的传参方式,虽然我没学过python,但我好像知道它并没有指针,如果没有指针,那它对象的参数传递方式一定是内存地址入栈(应该不会学诡异的C#,class地址传但struct只能值传,且不能为空),至于它究竟叫引用传递还是地址传递什么的,千万不要死磕名词!
【 在 HB0318 的大作中提到: 】
: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
: 答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
: Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
: ...................
讲的很透彻明白,赞一个
【 在 NotEnough 的大作中提到: 】
: 知乎用多了,我用知乎式的长篇大论尝试解释一下。
: 估计lz是没学C系语言吧,有些人解释高级语言参数传递爱搞什么值传递、引用传递、地址传递来解释,本来是想降低理解学习难度,但实际却越搞越乱。
: 为什么会有参数传递?函数调用才产生的参数传递,函数调用时会发生入栈,所以首先得理解栈模型。函数参数会在函数调用时压入栈,如果你是语言设计者,你怎么把函数要用到的参数压入栈?
: ...................
来自「北邮人论坛手机版」