- 浏览: 304579 次
- 性别:
- 来自: 天津
文章分类
最新评论
-
suxiaojack:
15题,就是拿杨辉三角填充空格,答案应该是C(38,19)吧? ...
Project Euler解题汇总 013 ~ 022 -
songhaikang:
这篇文章挺好的,跟着你的步骤很快就可以入门了。非常感谢。
[转贴]Derby入门 —— (1) -
Eastsun:
呵呵,我没有Android的机器,所以兴趣不大
使用Java写的GVmaker虚拟机(开源) -
crapricorn:
那个版本的用不了虚拟键盘啊 呵呵 我们的手机没有实体键盘呀 所 ...
使用Java写的GVmaker虚拟机(开源) -
Eastsun:
crapricorn 写道希望sun侠能做出个android平 ...
使用Java写的GVmaker虚拟机(开源)
前言:在JAVA面试题解惑系列(五)——传了值还是传了引用?中作者提到了“JAVA中的传递都是值传递吗?有没有引用传递呢? ”这个问题,最终得到:
事实上有着这种想法的人为数不少。但这个结论不完全正确。正确的说法应该是:在Java中,只有按值传递,没有按引用传递!
简单说,这里其实就是一个关于什么是“按引用传递”的问题。
如果你写了这样一个方法:
并且像下面这样调用该方法:
确实能调换var1与var2的值,才可能是“按引用传递”
有关这个问题的进一步解释,我这儿不再赘述,只给出两篇不错的文章:
☆ Does Java pass by reference or pass by value?
☆ Java is Pass-by-Value, Dammit!
下面是第二篇的全文,有空再翻译:
Introduction
I finally decided to write up a little something about Java's parameter passing. I'm really tired of hearing folks (incorrectly) state "primitives are passed by value, objects are passed by reference".
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
Pass-by-value
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.
Pass-by-reference
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.
Java is strictly pass-by-value, exactly as in C. Read the Java Language Specification (JLS). It's spelled out, and it's correct. (See http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#37472)
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
If you can write such a method/function in your language such that calling
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 }
...
{ in some other procedure/function/program }
or in C++ you could write
...
(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
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
shows that Java does in fact pass objects by reference.
The mistake they make is in the definition of
itself. When you write
you are defining a pointer to a Dog object, not a Dog object itself.
Calling
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,
is exactly like C or C++'s
And using
is exactly like C++'s
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
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.)
A Note on Remote Method Invocation (RMI)
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).
正解
从说法上来说,THE Java™ Programming Language, Fourth Edition
All parameters to methods are passed "by value."
Some people will say incorrectly that objects are passed "by reference." In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory.The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing modepass by valueand that helps keep things simple.
这里对程序设计语言中的术语pass by reference 有明确的解释。
但我感觉出问题的源头还是java对引用的定义,引用在C++中已经有明确的意义了,而java为了避免指针的说法采用了引用,不过这种引用其实就是一种指针,在c++中,引用就是别名,而java不是。从方法调用来看,对于引用类型参数来说,和C/C++中的传指针是类似的,你可以修改指针指向的内容,但是你修改了指针本身的值的话就没什么效果了。
看这个例子:
但是和C++的引用传递就明显不同了。这就不用举例了。
最后我感觉,java的设计者们改变了reference的语义,为了方法传参模型的简单,又只定义了一个值传递的模式。没有定义新的pass by reference 的语义,这才导致了这种争论。
概念问题没太多讨论意义?你能保证java能写一辈子,以后有需求需要你写点c,那不是...
引用
最后我们得出如下的结论:
1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。
1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。
事实上有着这种想法的人为数不少。但这个结论不完全正确。正确的说法应该是:在Java中,只有按值传递,没有按引用传递!
简单说,这里其实就是一个关于什么是“按引用传递”的问题。
如果你写了这样一个方法:
swap(Type arg1, Type arg2) { Type temp = arg1; arg1 = arg2; arg2 = temp; }
并且像下面这样调用该方法:
Type var1 = ...; Type var2 = ...; swap(var1,var2);
确实能调换var1与var2的值,才可能是“按引用传递”
有关这个问题的进一步解释,我这儿不再赘述,只给出两篇不错的文章:
☆ Does Java pass by reference or pass by value?
☆ Java is Pass-by-Value, Dammit!
下面是第二篇的全文,有空再翻译:
Introduction
I finally decided to write up a little something about Java's parameter passing. I'm really tired of hearing folks (incorrectly) state "primitives are passed by value, objects are passed by reference".
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
Pass-by-value
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.
Pass-by-reference
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.
Java is strictly pass-by-value, exactly as in C. Read the Java Language Specification (JLS). It's spelled out, and it's correct. (See http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#37472)
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.)
A Note on Remote Method Invocation (RMI)
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).
评论
33 楼
风雪涟漪
2009-01-13
按值传递的。。还和同事争执过。。。具体详见 java核心卷。
32 楼
binlaniua
2009-01-12
rxgp02a 兄 说的很明白了
不管传进来的是什么 JVM都会为其创建一个 副本的
不管传进来的是什么 JVM都会为其创建一个 副本的
31 楼
sdh5724
2009-01-11
本着认真的负责, 我刚仔细看了下
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
这个文章的作者根本不懂JAVA, 用这么个例子说的是传引用:
public void tricky(Point arg1, Point arg2)
{
arg1.x = 100;
arg1.y = 100;
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
}
public static void main(String [] args)
{
Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);
System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
System.out.println(" ");
tricky(pnt1,pnt2);
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}
通过一个方法调用, 制造一个表面上相同的对象。
实质上, 传值要做对象copy的。 这就成大忌了。
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
这个文章的作者根本不懂JAVA, 用这么个例子说的是传引用:
public void tricky(Point arg1, Point arg2)
{
arg1.x = 100;
arg1.y = 100;
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
}
public static void main(String [] args)
{
Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);
System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
System.out.println(" ");
tricky(pnt1,pnt2);
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}
通过一个方法调用, 制造一个表面上相同的对象。
实质上, 传值要做对象copy的。 这就成大忌了。
30 楼
wendong007
2009-01-11
<div class='quote_title'>sdh5724 写道</div>
<div class='quote_div'>基础类型, string是值传递。 不过, string比较特别。<br/>其他所有继承Object对象的东西, 都是引用。 因为JAVA实际上, 说的不好听点, 任意时刻任何实例都是全JVM可见的,不然GC就管理不到它了, 看你用角度看这个理解。 整天不F规范上说的人还真不少。 别总觉得E文的技术文章就是真理哦。</div>
<p> </p>
<p>String类型一样也是引用传递,只不过你不能改变String对象的内容而已,看起来似乎是值传递,如果你自己构造一个只能在构造方法中初始化对象状态,而没有任何改变对象状态的方法类,这个类和String也是一样的</p>
<div class='quote_div'>基础类型, string是值传递。 不过, string比较特别。<br/>其他所有继承Object对象的东西, 都是引用。 因为JAVA实际上, 说的不好听点, 任意时刻任何实例都是全JVM可见的,不然GC就管理不到它了, 看你用角度看这个理解。 整天不F规范上说的人还真不少。 别总觉得E文的技术文章就是真理哦。</div>
<p> </p>
<p>String类型一样也是引用传递,只不过你不能改变String对象的内容而已,看起来似乎是值传递,如果你自己构造一个只能在构造方法中初始化对象状态,而没有任何改变对象状态的方法类,这个类和String也是一样的</p>
29 楼
wendong007
2009-01-11
<p><span style='font-family: -webkit-monospace; white-space: pre-wrap;'><span style='font-size: large;'>我觉得这个讨论没有多大意义,大家都知道怎么用而且能够达成共识也就可以了,如果真的要讨论的话,LZ说的这种C++中的按引用传递还不如叫按指针传递,因为C/C++中任何类型包括(指针类型在内)都可以再定义一个指针指向该数据,才会出现这种“按指针传递”的方式,Java这种没有指针类型的语言当然不会有这种“按指针传递”,但是Java中的对象确实存在一个引用,说他是按引用传递也没什么错误,干吗非要扯的那么清楚呢,我觉得LZ和LZ引用的那篇文章的作者的想法,是对“按引用传递”的一种曲解</span></span></p>
28 楼
sdh5724
2009-01-11
基础类型, string是值传递。 不过, string比较特别。
其他所有继承Object对象的东西, 都是引用。 因为JAVA实际上, 说的不好听点, 任意时刻任何实例都是全JVM可见的,不然GC就管理不到它了, 看你用角度看这个理解。 整天不F规范上说的人还真不少。 别总觉得E文的技术文章就是真理哦。
其他所有继承Object对象的东西, 都是引用。 因为JAVA实际上, 说的不好听点, 任意时刻任何实例都是全JVM可见的,不然GC就管理不到它了, 看你用角度看这个理解。 整天不F规范上说的人还真不少。 别总觉得E文的技术文章就是真理哦。
27 楼
石建武
2009-01-11
如果传的是基本数据类型,修改这个值并不会影响作为参数传进来的那个变量,因为你修改的是方法的局部变量,是一个副本。
如果传的是一个对象的引用,也是一样的,也是一个副本,但是这个副本和作为参数传进来的那个引用指向的是内存中的同一个对象,所以你通过这个副本也可以操作那个对象。但是如果你修改这个引用本身,比如让他指向内存中的另外一个对象,原来作为参数传进来的那个引用不会受到影响。
我觉得弄明白这些就行了,说值传递或引用传递都无所谓,但是说值传递更适合一些,这个值可以是引用也可以是基本数据类型。
--------- 引用他人的话
所有的调用都是按值传递这是没错的,因为调用堆栈的原理限定了我们只能将各种值压入堆栈,而方法返回时,并不会将堆栈中的值再进行处理,而只是简单的调整栈顶指针将原先压入堆栈的值废弃掉。所以,一切对压栈而传递到方法体内的参数,方法内部所做的修改对外界都是无法看到的。那么鉴于这种情况,为了将函数内部对参数的修改可以带到函数外,各种语言做了不同的处理,C/C++中可以传递指针,而Java则默认传递对象的引用。如果楼主非要把方法调用时压入堆栈的地址称为值的话,其实也并非不可,只不过这种说法我觉得有点儿牵强了。
--------- 引用他人的话
同意两位的意见!谢谢
如果传的是一个对象的引用,也是一样的,也是一个副本,但是这个副本和作为参数传进来的那个引用指向的是内存中的同一个对象,所以你通过这个副本也可以操作那个对象。但是如果你修改这个引用本身,比如让他指向内存中的另外一个对象,原来作为参数传进来的那个引用不会受到影响。
我觉得弄明白这些就行了,说值传递或引用传递都无所谓,但是说值传递更适合一些,这个值可以是引用也可以是基本数据类型。
--------- 引用他人的话
所有的调用都是按值传递这是没错的,因为调用堆栈的原理限定了我们只能将各种值压入堆栈,而方法返回时,并不会将堆栈中的值再进行处理,而只是简单的调整栈顶指针将原先压入堆栈的值废弃掉。所以,一切对压栈而传递到方法体内的参数,方法内部所做的修改对外界都是无法看到的。那么鉴于这种情况,为了将函数内部对参数的修改可以带到函数外,各种语言做了不同的处理,C/C++中可以传递指针,而Java则默认传递对象的引用。如果楼主非要把方法调用时压入堆栈的地址称为值的话,其实也并非不可,只不过这种说法我觉得有点儿牵强了。
--------- 引用他人的话
同意两位的意见!谢谢
26 楼
xwyzl
2008-12-01
MarkDong 写道
楼主的说法有点儿牵强,所有的调用都是按值传递这是没错的,因为调用堆栈的原理限定了我们只能将各种值压入堆栈,而方法返回时,并不会将堆栈中的值再进行处理,而只是简单的调整栈顶指针将原先压入堆栈的值废弃掉。所以,一切对压栈而传递到方法体内的参数,方法内部所做的修改对外界都是无法看到的。
那么鉴于这种情况,为了将函数内部对参数的修改可以带到函数外,各种语言做了不同的处理,C/C++中可以传递指针,而Java则默认传递对象的引用。如果楼主非要把方法调用时压入堆栈的地址称为值的话,其实也并非不可,只不过这种说法我觉得有点儿牵强了。
那么鉴于这种情况,为了将函数内部对参数的修改可以带到函数外,各种语言做了不同的处理,C/C++中可以传递指针,而Java则默认传递对象的引用。如果楼主非要把方法调用时压入堆栈的地址称为值的话,其实也并非不可,只不过这种说法我觉得有点儿牵强了。
正解
25 楼
ph3120
2008-10-19
其实传的是什么关键是看个人的理解了。。不管怎么样只要结果是对的就好。。我个人的理解是在这个传递过程中存在的都是值传递。。及传递的都是变量本身的值。基本数据类型传的就是本身那个值。引用类型的是Object中toString()打印出的值。对象本身的值是在保存在内存的堆里面的。不会随便把整个值进行交换的。。交换的是保持在内存中栈中的引用的值。。其实那些觉得是交换了对象本身的值的可以很简单的就验证出来的。。你定义两个引用指向同一个对象。然后在那另外一个对象的引用与这其中的一个进行交换。。然后打印出那个没参与交换的引用指向那个对象的值就很清楚了!
24 楼
blackboy_my
2008-10-17
<p>一开始被你的一句话给吓到了,其实说到底,我们都是动物,,是和这个道理一样吧~~~~</p>
<p>我不同意你的看法~~不好意思,不支持你。</p>
<p> </p>
<p>我不同意你的看法~~不好意思,不支持你。</p>
<p> </p>
23 楼
czlonly
2008-10-17
其实数组还是引用,说泛一点变量都是引用,只不过是被隐藏了
22 楼
寄生虫
2008-10-17
无聊的争论
21 楼
lanshan
2008-10-17
C代码
Type var1 = ...;
Type var2 = ...;
swap(var1,var2);
这里定义的两个对象就是引用 指向内存中存储数据的地址
C代码
swap(Type arg1, Type arg2) {
Type temp = arg1;
arg1 = arg2;
arg2 = temp;
}
而在这块实际上arg1,arg2是两个新的引用也是指向内存中存储数据的地址
当你做交换的时候 实际交换arg1和arg2两个引用 就是将arg1的引用指像arg2引用所指像的地址而arg2引用指向arg1的地址,,,而不会改变内存中数据存储的地址,
而var1和var2的引用的并没有被改变,,,还是指像原本的地址 。。。
这就是java的引用传递和C++引用传递的区别。。。。。C++传递会改变内存地址中的数据存储位置 和JAVA不会 它只会改变对象引用的指向 而不会更改内趣中地址所存储的数据
Type var1 = ...;
Type var2 = ...;
swap(var1,var2);
这里定义的两个对象就是引用 指向内存中存储数据的地址
C代码
swap(Type arg1, Type arg2) {
Type temp = arg1;
arg1 = arg2;
arg2 = temp;
}
而在这块实际上arg1,arg2是两个新的引用也是指向内存中存储数据的地址
当你做交换的时候 实际交换arg1和arg2两个引用 就是将arg1的引用指像arg2引用所指像的地址而arg2引用指向arg1的地址,,,而不会改变内存中数据存储的地址,
而var1和var2的引用的并没有被改变,,,还是指像原本的地址 。。。
这就是java的引用传递和C++引用传递的区别。。。。。C++传递会改变内存地址中的数据存储位置 和JAVA不会 它只会改变对象引用的指向 而不会更改内趣中地址所存储的数据
20 楼
suerzxt
2008-09-04
Eastsun 写道
归根究底,其实就是一个对“按引用传递”这个概念理解的问题。
如果你非得说“按引用传递”,那么得重新定义一个与C++中“按引用传递”不同的概念出来。
如果你非得说“按引用传递”,那么得重新定义一个与C++中“按引用传递”不同的概念出来。
从说法上来说,THE Java™ Programming Language, Fourth Edition
All parameters to methods are passed "by value."
Some people will say incorrectly that objects are passed "by reference." In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory.The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing modepass by valueand that helps keep things simple.
这里对程序设计语言中的术语pass by reference 有明确的解释。
但我感觉出问题的源头还是java对引用的定义,引用在C++中已经有明确的意义了,而java为了避免指针的说法采用了引用,不过这种引用其实就是一种指针,在c++中,引用就是别名,而java不是。从方法调用来看,对于引用类型参数来说,和C/C++中的传指针是类似的,你可以修改指针指向的内容,但是你修改了指针本身的值的话就没什么效果了。
看这个例子:
#include <iostream> using namespace std; class Test { public: int a; }; void change(Test* test){ test->a=5; test=new Test(); test->a=8; } int main() { Test* t=new Test(); change(t); cout<<t->a<<endl; }
但是和C++的引用传递就明显不同了。这就不用举例了。
最后我感觉,java的设计者们改变了reference的语义,为了方法传参模型的简单,又只定义了一个值传递的模式。没有定义新的pass by reference 的语义,这才导致了这种争论。
19 楼
tinywind
2008-08-13
同意lz的意见,值传递和引用传递本来都有明确的含义,java程序员不应该轻易破坏这些约定。
18 楼
kjj
2008-08-12
为什么现在都喜欢把简单问题复杂化,不理解
17 楼
nowonder
2008-08-12
norwolfli 写道
这应该是新手帖吧,可惜我评不了啊.
对于概念性的问题讨论太多没意义.
对于概念性的问题讨论太多没意义.
概念问题没太多讨论意义?你能保证java能写一辈子,以后有需求需要你写点c,那不是...
16 楼
nowonder
2008-08-12
java感觉应该还算是引用传递啊
A a=new A();
其实a只是一个8字节指向堆地址的引用,而对另外一个B b=a;也只是将这个堆地址扔给了b.
而基础类型的值传递,也只是这个引用指向了栈区的常量池(不是很确定在栈)。
所以感觉这问题是怎么理解引用传递的吧?如果把堆地址就看做值的话,那就可以说是值传递了.不过就算说是值传递,其实跟引用传递本质有区别么?
A a=new A();
其实a只是一个8字节指向堆地址的引用,而对另外一个B b=a;也只是将这个堆地址扔给了b.
而基础类型的值传递,也只是这个引用指向了栈区的常量池(不是很确定在栈)。
所以感觉这问题是怎么理解引用传递的吧?如果把堆地址就看做值的话,那就可以说是值传递了.不过就算说是值传递,其实跟引用传递本质有区别么?
15 楼
norwolfli
2008-08-12
这应该是新手帖吧,可惜我评不了啊.
对于概念性的问题讨论太多没意义.
对于概念性的问题讨论太多没意义.
14 楼
grandboy
2008-08-10
什么值传递,什么值传递的,如果在面试的时候出这种题就有点弱智了。还不如干脆写出来一段程序让面试者写出输出结果呢。这样可以避免大家对概念的理解不一致的问题。
发表评论
-
JavaFX1.2的性能貌似有了很大的提升
2009-06-03 09:36 1939Osvaldo Pinali Doederlein's B ... -
Java.next:第二部分——与Java互操作
2008-09-19 23:05 1840原文地址:Java.next #2: Java Inter ... -
Java.next:第一部分——共同点
2008-09-19 13:31 1503原文地址:Java.next: Common Ground ... -
隐式转换:比动态类型更强大?
2008-09-16 18:37 1644本文内容主要来自Implicit Conversions: ... -
Ruby,Python不能威胁到Java的13个理由
2008-05-28 22:50 1438最近,danielstoner发表了一篇题为13 reas ... -
Java:进化的尽头
2008-05-28 17:45 1269原文地址:http://blog. ... -
《Effective Java》: Joshua Bloch访谈
2008-05-23 00:52 2564原文地址:Effective ... -
JSR 308:Java语言复杂度在恣意增长?
2008-05-20 13:54 1728原帖地址:http://www ... -
Sun能否让Java重振雄风?
2008-05-13 14:42 0原文地址:Can Sun rejuvenate Java? ... -
Groovy, JRuby, Jython, Scala:谁是胜利者?
2008-05-13 00:04 6526原文地址:Groovy, JRuby, Jython, Sca ... -
JAVA比C++更快?
2008-04-08 15:03 2013首先:我必须承认,我取JA ... -
在J2ME中模拟C语言中的文件操作
2008-02-27 00:09 1571最近在写一个模拟器(OR虚拟机),用于运行文曲星(一种 ... -
使用StAX解析XML:使用定制事件和编写 XML
2007-10-12 23:01 2063除了提供一个低层的基 ... -
使用StAX解析XML: 拉式解析和事件
2007-10-08 20:53 32862007 年 7 月 05 日 Streaming API ... -
[转载]Streaming API for XML (StAX) 简介
2007-10-07 13:35 2271Streaming API for XML (StAX) 是用 ... -
使用CookieHandler管理Cookie数据
2007-05-31 23:22 10847前言 : 因为只学过J2SE部分,对JAVA网络编程也不甚了 ... -
浅谈HTTP的无状态性
2007-05-30 01:26 2003HTTP是Hyper Text Transf ... -
用动态代理进行修饰
2007-04-11 16:26 1807动态代理为实 ... -
一种得到代码所在行号的方法
2007-04-02 20:03 3893RT,今天在论坛上看到有人提出这个问题,马上联想 ... -
网络词汇表
2007-04-01 13:33 1957【协议 】--- protocol,指通信双方通信时遵守的一 ...
相关推荐
澄清Java(接口与继承)
java六大必须澄清的概念 经常会遇到的面试题目 来自网络少许有误
java开发oa系统源码下载 1. 内容 1.1. 理论 1.1.1. 单元测试/日志记录/性能[R] 单元测试 记录: 区分与日志级别相关的概念 参考:+上面的关键字 澄清吞吐量和延迟的概念,P99。 (这些参数的含义) 1.1.1.1. 单元...
+观测值,2000+样本企业!涵盖澄清公告内容、传闻类型、传播媒体等重要指标,数 据真实可靠,极具研究价值! 本数据集由权威方法测算,经过多 次校验确保100%准确无误,回归显著性极好,由本人及所在课题组独家整理...
水力澄清池计算
制糖澄清pH值控制系统神经网络建模
中广核新能源:澄清公告有关2020年度报告.PDF
启发式动态规划在糖厂澄清工段pH值控制中的应用
要运行该软件包:java -jar target / trade-order-book-0.0.1-SNAPSHOT.jar 实现的API: 金融工具订单簿的打开/关闭URL: 请求:{“ instrumentId”:“ BITCOIN”,“ orderBookStatus”:“ O”} 响应:HTTP响应...
某集团战略澄清报告.pptx
有关更多信息,请参阅审核,有关 bot 的澄清、问题和疑问请联系开发团队 :laptop: 命令:B>card = 请求并接收一张独特的卡片并输入宾果游戏! :ticket: B>draw = 绘制一个新数字(仅限版主和管理员) :NEW_button:...
岗位职责澄清与组织结构分析.pptx
第1章 Java概述、安装及简易教学 14 1-1 Java概述 14 1-2 Java安装 16 1-3 Eclipse安装 18 1-4 GUI设计工具WindowBuilder 18 1-5 在Eclipse开发第一个Java程式 23 1-6 在Eclipse开发第一个Java视窗程式-显示影像 26 ...
澄清几个基本概念-迅为精英版聊天记录 【泰斗】TOPEET迅为(1147135986) 21:36:19 公布答案:Linux是在运行的最后才挂载文件系统!
SynTime的源代码和数据集直接从Eclipse导出的Java项目中上传,因此可以直接导入到Eclipse。 导入项目后,您需要先导入Stanford CoreNLP模型,然后再运行它。 在我们的实现中,我们使用其3.6.0版本的CoreNLP模型,...
澄清技术规格书中问题.docx
本第3版的H.263 纳入了以前已分别通过和出版的附件U、V、W和X,并做了如下一些更正和澄清: • 更正图8; • 对表1内容的澄清,关于BPPmaxKb表和图像内容; • 对5.3.2内容的澄清,关于填充先导一个起始码的宏块; ...
电子行业日报:三安光电发布澄清公告.pdf
在该系统中,开发人员可以输入Java项目目录,该目录或子目录中包含Java源代码文件。 然后,系统将通过首先计算代码行(LOC),Halstead度量标准和Cyclomatic Complexity来计算可维护性指数,该系统将以表格形式显示...