`
jiopi
  • 浏览: 32170 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

也谈Java值传递-到底传递了什么?

    博客分类:
  • Java
阅读更多

java里面只有值传递,这是不变的真理,不过由于对象类型的特殊性,有些人还是会疑惑 值传递?还是 引用传递?

可能主要是这句话造成的: 在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。

如果java里面只有值传递,为何又要说对象是 引用传递?

 

对于 基本数据类型 是值传递,相信没有人会有疑惑。那对象到底传递了什么?

 

其实这源于JAVA在解释其变量类型时的一个混淆:JAVA里面只有8种基本数据类型和对象类型

 

于是便有了 基本数据类型是传递值,对象是传递引用

 

其实如果把对象类型也解释成一种 基本数据类型 ,那就不会出现 对象是传递引用 这句话让人疑惑的话了

 

下文将 对象类型 看成一种新的 基本类型, 姑且称之为 olong (object long),即 所有对象变量 都是 olong,虽然在java书写时可以写成具体的对象类型,如 Long a; 但其传递实质是  olong a;

 

让我们来重新认识 olong 吧:

 

赋值:

long a = 1234;

olong oa = new Long(1234); //Long oa = new Long(1234);

 

传递:

long b = a;

olong ob =oa;  //Long ob = oa;

 

改变:

b = 4321;

ob = new Long(4321); //ob = new Long(4321);

 

改变了什么?:

System.out.println(a); //输出 1234

System.out.println(b); //输出 4321

System.out.println(oa.longValue()); //输出 1234

System.out.println(ob.longValue()); //输出 4321

 

到底传递了什么:

long:

long a = 1234; //a的值1234

long b = a;//值传递 b的值1234;a的值1234

b = 4321;//b的值被改变为4321;但a不受影响,依然是1234

 

olong:

long类型的变量保存和传递的是其指代的基本类型的值,那么olong呢?

可以认为olong类型的变量保存和传递的是一个指向具体对象的内存地址,

olong oa = new Long(1234);//假设new Long生成的对象的地址为0001,则oa的值为0001

olong ob =oa; //值传递,ob的值0001;oa的值0001

ob = new Long(4321);//ob的值被赋予一个新的对象的地址,假设为0002,但oa的值不受影响,依然为0001

因此olong类型的赋值结果与long类型的表现一致,也是值传递

 

为什么对象是传递引用?

其实这句话也不错,因为olong变量本身就是一个引用,引用了一个对象(的内存地址)

但其实质是 值传递!只不过因为 olong 的值 还有一个 别名 叫做 引用,所以就被叫做了一个让人迷惑的新词:引用传递!

 

总结:

olong的引入只是为了方便解释Java对象的值传递,说明在参数传递过程中,对象变量的传递和基本变量的传递是没有本质区别的,所以,在Java中,没有 引用传递,只有值传递

分享到:
评论
22 楼 yongyuan.jiang 2010-05-06  
yongyuan.jiang 写道
值传引用传是对于语言级别的不同,按传的内容理解是错的。应该按不同的传递方式所产生的效果理解。

引用传递是c++里面的东西,在调用中可以声明传递引用,那么在子方法调用中改变该引用的指向,外部方法的引用同样改变。

java语言中无法声明引用传递,在子方法中改变了该引用的指向,外部方法的引用不变。

java的值传递引用传递说法是被很多人误导了。对于在子方法中通过调用对象的set方法从而改变了值,这不是引用传递,这种类似于引用传递的叫法是什么呢?见:http://en.wikipedia.org/wiki/Evaluation_strategy

Call by sharing
21 楼 yongyuan.jiang 2010-05-06  
值传引用传是对于语言级别的不同,按传的内容理解是错的。应该按不同的传递方式所产生的效果理解。

引用传递是c++里面的东西,在调用中可以声明传递引用,那么在子方法调用中改变该引用的指向,外部方法的引用同样改变。

java语言中无法声明引用传递,在子方法中改变了该引用的指向,外部方法的引用不变。

java的值传递引用传递说法是被很多人误导了。对于在子方法中通过调用对象的set方法从而改变了值,这不是引用传递,这种类似于引用传递的叫法是什么呢?见:http://en.wikipedia.org/wiki/Evaluation_strategy
20 楼 ironsabre 2010-04-23  
jameswxx 写道
没有想到这个问题还会引起这么多资深人士的口水。

其实很简单,如果大家先不想java的值传递和引用传递,c的传递大家应该都清楚吧,说穿了,所谓的引用传递不就是类似于c的指针吗?指针本身就是一个值,所以总的说来,java就是值传递。

Object a=new Object();
先创建了一个指向Object类型的引用对象 a.
再创建一个Object对象
然后将刚刚创建的Object对象的地址给a
这正如数据库的索引和表一样,一个索引项存储了指向某一行的实际地址。

Object b=a;
先创建了一个指向Object类型的引用对象 b.
然后将a的值(指向某一个对象的应用)复制传递一份给b
相当于又建立了一个索引项,该索引项存储的行地址和刚才那个索引项一样

b.set****()方法会引起a的属性的改变,因为两个都指向同一个地址。

b=new Object();
给b赋值了一个新的引用,现在b和a已经没有关系,对b的修改不会影响到a。



还不清楚的,建议好好把大学时候的c语言指针抱起来看看吧!




简单的理解就是,简单类型传值,真正的值,对象是传引用的副本。

但如果向这位大哥说的,引用本身也是一个值,所以都是值传递,那这就有点咬文嚼字了,那我就没话说了。
19 楼 xiaojing3517 2010-04-23  
啊哦。。。。果真杯具了。。。。
18 楼 20055294 2010-04-23  
学习各位 的精华了
17 楼 xiaojing3517 2010-04-23  
楼主似乎要杯具了,再投几票。。。
16 楼 smilerain 2010-04-23  
你们都是说的付值吧!
付值当然是,有就引用,没有就创建了。
没有这个值它去引用什么?
15 楼 jiopi 2010-04-23  
zhxing 写道
双重检查锁定的根源是因为JVM 的优化导致乱序执行吧。。不知道你说的和值传递有什么关系??


我引入一个 olong 来解释对象的引用传递,就是不想 把 堆 栈 指针 等等 这些名词引入,因为本来Java也是打算回避这些问题的,但我认为就是因为 "对象是引用传递" 这个解释,很多本来可以简单理解的内容,被搞复杂了

因为 "对象是引用传递" 其实是两个层面:
1.对象变量(也就是我引入的olong类型)是值传递
2.传递的值代表的是 对象的"引用"

另外解释一下olong的命名原因:
不是因为我的参照对象是Long才叫olong的
而是我假设这个变量保存的也是一个long类型的数据(内存地址),只不过这个long的值表示的不是一个数字,而是一个对象的引用,当然,到底java是怎么保存对象变量的,我认为无需关心

就拿 volatile 来说吧,本来 synchronized 够用了

但 synchronized 被设计成了 引用 锁定,即 对 olong变量的值所指向的那个 对象 进行锁定

用olong解释,就是 如果 加锁对象的olong值相同 ,操作会被互斥,即使 是多个 olong 变量

这样问题就来了,synchronized 不能锁定 null ,即 如果 olong变量的值 指向的是 null (假设其值是-1)

这样一来 双重检查锁定 就出问题了

先回顾一下 代码吧
if (instance == null)// 1:instance的olong值为-1
  {
    synchronized(Singleton.class) {  
      if (instance == null)          //2:判断如果instance的olong值为-1
        instance = new Singleton();  //3: 给 instance的这个olong变量一个新的值,假设为0001
    }
  }

在多CPU的多线程环境里,因为优化,不同CPU在执行代码时,当涉及对instance的调用时,每个CPU都事先拿了instance的值的拷贝(再次值传递),假设不同CPU中的新olong为instance1 instance2 ,如果是调用对象的方法,自然不会出问题了,因为每个CPU拿到的值都相同

但在 双重检查锁定 中, 标注 3 的语句对 instance 这个olong进行了重新赋值,步骤应该是CPU1首先改写 instance1的值,然后再改写 instance 的值,但如果没有  volatile 值锁定,CPU2在CPU1解除Singleton.class锁定后运行到语句2时,本地拷贝 instance2 的值就可能还是 -1

于是双重检查锁定失效

所以 volatile 的值锁定 解决了 双重检查锁定失效 的问题
14 楼 jameswxx 2010-04-23  
没有想到这个问题还会引起这么多资深人士的口水。

其实很简单,如果大家先不想java的值传递和引用传递,c的传递大家应该都清楚吧,说穿了,所谓的引用传递不就是类似于c的指针吗?指针本身就是一个值,所以总的说来,java就是值传递。

Object a=new Object();
先创建了一个指向Object类型的引用对象 a.
再创建一个Object对象
然后将刚刚创建的Object对象的地址给a
这正如数据库的索引和表一样,一个索引项存储了指向某一行的实际地址。

Object b=a;
先创建了一个指向Object类型的引用对象 b.
然后将a的值(指向某一个对象的应用)复制传递一份给b
相当于又建立了一个索引项,该索引项存储的行地址和刚才那个索引项一样

b.set****()方法会引起a的属性的改变,因为两个都指向同一个地址。

b=new Object();
给b赋值了一个新的引用,现在b和a已经没有关系,对b的修改不会影响到a。



还不清楚的,建议好好把大学时候的c语言指针抱起来看看吧!


13 楼 zhxing 2010-04-23  
jiopi 写道
理解值传递当然重要!著名的双重检查锁定(double-checked-locking)问题根源就是值传递,volatile 锁定的也是 值 而不是 引用


双重检查锁定的根源是因为JVM 的优化导致乱序执行吧。。不知道你说的和值传递有什么关系??
12 楼 tczengjin 2010-04-23  
ironsabre 写道
akiraray 写道
piao_bo_yi 写道
所有东西都是值传递,但是这句话是废话。
JAVA,基本类型是值传递,其他是传递的引用的拷贝。

Java just pass by value……
当然我本科时候的教科书上面写java还有引用传递……完全误人子弟


我觉得你没懂。


方法传参本质都是将值拷贝压堆栈,方法结束拷贝消失,c语言不也这样吗
java的引用我的理解就是不可计算的指针,但寻址寻值方式是和c没有区别的
本科书籍采购是有清单,如果清单的书都是烂书,也许你老师只能在烂书中
挑本好的,也不排除写书的人水平低或者作者认为本科生水平低写成这样
11 楼 lzj0470 2010-04-23  
呵呵。受教了~
10 楼 ironsabre 2010-04-23  
akiraray 写道
piao_bo_yi 写道
所有东西都是值传递,但是这句话是废话。
JAVA,基本类型是值传递,其他是传递的引用的拷贝。

Java just pass by value……
当然我本科时候的教科书上面写java还有引用传递……完全误人子弟


我觉得你没懂。
9 楼 jerry1985 2010-04-23  
到底是值传递还是引用传递已经没什么可讨论的了。
8 楼 wangzaixiang 2010-04-23  
唉,搞了十多年Java了,最让我晕的就是这个话题了。

1、www.csdn.net上有一个叫做“钟声”的专家,有一本大作:《上班那点事儿》的,有一个博文就与这个有关的。http://blog.csdn.net/useway/archive/2009/09/14/4551049.aspx。当然,那里的主题是 Java中有没有指针。

Java中有没有指针呢?有,还是没有?可以有?还是不可以有?真的可以有?还是真的没有?可惜没几个相声演员懂程序,要不,是一段精彩的段子。

2、我原来有一个小兄弟,对这个话题也是乐此不疲,钻研了很久,还遍查资料,也写了不少文章。可以参考:http://jiangyongyuan.iteye.com/blog/593768、http://jiangyongyuan.iteye.com/blog/450687

到底是传值呢?还是传址呢?这是个问题?问问CPU吧,CPU也不知道,它就懂0/1而已。各位有兴趣研究的人,继续思考这个问题吧,我头晕得很,先退出去。
7 楼 newid 2010-04-22  
对于在java里楼主这样的测试的想法就不对,
如果你这样
Bean a = new Bean();
a.setId(1)
Bean b = a;
b.setId(2);

System.out.println(a.getId());
System.out.println(b.getId());
你再看看呢,值是不是变了。
6 楼 akiraray 2010-04-22  
piao_bo_yi 写道
所有东西都是值传递,但是这句话是废话。
JAVA,基本类型是值传递,其他是传递的引用的拷贝。

Java just pass by value……
当然我本科时候的教科书上面写java还有引用传递……完全误人子弟
5 楼 piao_bo_yi 2010-04-22  
所有东西都是值传递,但是这句话是废话。
JAVA,基本类型是值传递,其他是传递的引用的拷贝。
4 楼 J-catTeam 2010-04-22  
·····好吧
3 楼 jiopi 2010-04-22  
理解值传递当然重要!著名的双重检查锁定(double-checked-locking)问题根源就是值传递,volatile 锁定的也是 值 而不是 引用

相关推荐

    java中只有值传递

    Java中传递对象时传递的并不是对象中的内容, 而是对象的地址。

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

    ### Java中的按值传递与按引用传递详解 #### 一、引言 在Java编程语言中,关于参数传递的方式一直存在两种观点:一种认为Java仅支持按值传递,另一种则指出Java同时支持按值传递和按引用传递。实际上,这两种观点...

    java 值传递和引用传递的比较

    在Java编程语言中,了解值传递和引用传递的概念至关重要,因为它们直接影响到函数参数的处理方式。下面将详细探讨这两个概念及其区别。 首先,我们来理解什么是值传递。在Java中,基本数据类型(如int、double、...

    java值传递与引用传递

    在Java编程语言中,函数参数的传递方式有两种:值传递和引用传递。理解这两种机制对于编写高效、无误的代码至关重要。以下是对这两种传递方式的详细解析。 首先,值传递是指函数调用时,实际参数的值被复制一份传给...

    谷歌java格式-重新格式化 Java 源代码以符合 Google Java 风格

    谷歌java格式 google-java-format是一个重新格式化 Java 源代码以符合 Google Java Style的程序。 使用格式化程序 从命令行 下载格式化程序 并运行它: java -jar /path/to/google-java-format-${GJF_VERSION?}-all...

    Java零基础-参数传递-2.md

    作为一门广泛使用的编程语言,Java提供了多种参数传递的方式,这其中包括了基本类型的值传递以及引用类型的地址传递。同时,文章还涵盖了可变参数列表(varargs)的使用方法以及如何在方法中正确地定义和使用返回值...

    Java零基础-参数传递-1.md

    1. **误解基本类型参数传递**:新手程序员有时会误以为基本类型的参数传递也可以像引用类型那样修改外部变量的值。 2. **忽略引用类型参数传递的特点**:未能充分利用引用类型参数传递的优势,如在方法内部直接修改...

    Java是值传递,传对象引用也是通过值

    标题“Java是值传递,传对象引用也是通过值”揭示了Java中参数传递的核心概念。Java总是以值传递方式进行,这意味着当你将一个变量作为参数传递给方法时,传递的是该变量所存储值的一个副本。然而,对于对象类型的...

    java参数传递时到底是值传递还是引用传递分享.pdf

    总的来说,Java的参数传递既可以说是值传递,也可以说是引用传递,取决于你如何定义“值”。重要的是理解,无论哪种理解,Java都保证了对象引用的不可变性,而对象的内容可以在方法内部被修改。在面试或讨论中,理解...

    Java面向对象值传递和引用传递

    Java 面向对象值传递和引用传递 Java 面向对象编程中,参数传递是非常重要的一个概念。参数传递有两种方式:值传递和引用传递。了解这两种方式的区别是非常重要的,因为它们对程序的执行结果产生了很大的影响。 值...

    java参数传递-1_20201207151148.jpg

    java

    值传递与引用传递-内存解析

    首先,我们要理解什么是值传递。在值传递中,当一个变量作为参数传递给函数时,函数接收到的是该变量当前值的一个副本。这意味着在函数内部对参数的任何修改都不会影响到函数外部的原始变量。例如,在C++或Java中,...

    java参数传递时到底是值传递还是引用传递[归类].pdf

    这也是为什么有人会说Java是值传递,因为传递的是对象引用的副本,而不是实际的对象;同时,也有人会说Java是引用传递,因为通过这个引用可以改变对象的内容。 引用传递和值传递的区别在于,如果语言支持真正的引用...

    Java 值传递Visio资源

    在Java中,参数传递有两种方式:值传递和引用传递。这个“Java 值传递Visio资源”包含了几个Visio图形文件,帮助我们直观地理解这两种传递方式。 1. **值传递**: 当方法调用时,对于基本类型(如int, double, char...

    重新格式化 Java 源代码以符合 Google Java 风格google-java-format v1.18.1.zip

    google-java-format是一个重新格式化Java源代码以符合Google Java风格的程序。格式化程序可以作用于整个文件、有限的行、特定的偏移,传递到标准输出(默认)或就地更改。格式化程序的格式化算法没有可配置性。这是...

    深入了解为什么Java中只有值传递?

    这也解释了为什么在 Java 中,我们可以改变对象的状态,但不能改变对象引用的值。这是因为方法得到的是对象引用的拷贝,而不是原始对象本身。 在 Java 中,对对象的参数传递是按值传递的,而不是按引用传递的。这...

    javabase64-1.3.1

    在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。 javabase64-1.3.1....

Global site tag (gtag.js) - Google Analytics