- 浏览: 289609 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
SpringJava:
摘过来的
小心使用ArrayList和LinkedList -
jingjing0907:
我要成为第一个赞的人!呵呵,
小心使用ArrayList和LinkedList -
SpringJava:
cilendeng 写道应该用ConcurrentHashMa ...
实现单用户登陆session先进先出(session踢出) -
lingxiajiudu:
不错,完美解决我了的问题,赞一个。
子窗体给父窗体传值 javascript opener -
cilendeng:
应该用ConcurrentHashMap
实现单用户登陆session先进先出(session踢出)
java方法用的是值传递还是引用传递。你在blogjava上还能搜到不同的答案呢。最近有空就翻译了一篇国外的文章,很多东西不能只看答案,而不知其所以然。第一次翻译文章,博友多指教。
重申:对于原始类型(primitive type也译为值类型),是通过拷贝一个相同的值传给java方法的参数的;而对于引用类型(reference type),就是对象,是通过拷贝一个相同的应用或地址传给java方法的参数的。业界都统称这是pass-by-value(值传递),这里是翻译一篇国外的文章来说明为什么java中的值传递比较特别。
java中值传递比较特别,也比较有争议,所以重要的是要理解它的原理。推荐Java程序员都去读《Effective java》。
原文地址:http://java.sun.com/developer/JDCTechTips/2001/tt1009.html
另一篇写的比较好的文章(英文):http://www.brpreiss.com/books/opus5/html/page590.html
blogjava上前辈的文章:http://www.blogjava.net/zygcs/archive/2008/10/05/232438.html
实际参数是如何传递到 java 方法的
( HOW ARGUMENTS ARE PASSED TO JAVA METHODS )
Suppose you're doing some Java programming, and you have a simple program like this:
假如你正在编写 java 程序,然后你写了以下一个程序:
2 static void f( int arg1) {
3 arg1 = 10 ;
4 }
5
6 public static void main(String args[]) {
7 int arg1;
8
9 arg1 = 5 ;
10
11 f(arg1);
12
13 System.out.println( " arg1 = " + arg1);
14 }
15 }
16
In the main method, the variable arg1 is given the value 5, and then passed as an argument to the method f . This method declares a parameter of the same name, arg1 , used to access the argument.
在 main 方法中,变量 arg1 赋值 5 ,然后作为实际参数传递到方法 f 。这个方法声明一个相同名字的形式参数 arg1 ,被用于访问实际参数 。
What happens when you run this simple program? The method f modifies the value of arg1 , so what value gets printed, 5 or 10? It turns out that 5 is the right answer. This implies that setting arg1 to 10 in method f has no effect outside of the method.
当你执行这个程序会发生什么事情呢?方法 f 修改了 arg1 的值,所以会打印什么呢, 5 还是 10 ?这里 5 是正确的答案。这就意味着在方法 f 中,将 arg1 设为 10 并不影响到方法的外部。
Why does it work this way? The answer has to do with the distinction between the pass-by-value and pass-by-reference approaches to passing arguments to a method. The Java language uses pass-by-value exclusively. Before explaining what this means, let's look at an example of pass-by-reference, using C++ code:
为什么呢?答案在于区分使用“值传递”方式和“引用传递”方式给方法传递参数。 Java 语言使用与众不同的“值传递”方式。在解释它的意思之前,让我们看看以下一个值传递的例子,这是用 C++ 写的。
2
3 using namespace std;
4
5 void f( int arg1, int & arg2)
6 {
7 arg1 = 10 ;
8 arg2 = 10 ;
9 }
10
11 int main()
12 {
13 int arg1, arg2;
14
15 arg1 = 5 ;
16 arg2 = 5 ;
17
18 f(arg1, arg2);
19
20 cout << " arg1 = " << arg1 << " arg2 = " << arg2 << endl;
22 }
23
Function f has two parameters. The first parameter is a pass-by-value parameter, the second a pass-by-reference one. When you run this program, the first assignment in function f has no effect in the caller (the main function). But the second assignment does, in fact, change the value of arg2 in main . The & in int& says that arg2 is a pass-by-reference parameter. This particular example has no equivalent in Java programming.
函数 f 有两个形参。第一个是值传递,第二个是引用传递。当你运行这个程序的时候,第一个参数赋值不影响调用者( main 函数)。但是第二个参数赋值却会,事实上,修改了 main 中 arg2 的值。在 int& 中的 & 表示 arg2 是一个引用传递的形参。这个特别的例子与 java 有所不同 。
So what does pass-by-value actually mean? To answer this, it's instructive to look at some JVM1 bytecodes that result from the following two commands:
那值传递到底是什么意思 ? 要回答这个问题,有需要看一下运行以下两行命令后的 JVM 的字节码 :
javac CallDemo1.java
javap -c -classpath . CallDemo1
Here is an excerpt from the output:
这里是输出的片段:
0 bipush 10
2 istore_0
3 return
Method void main(java.lang.String[])
0 iconst_5
1 istore_1
2 iload_1
3 invokestatic # 2 < Method void f( int ) >
In the main method, the instruction iconst_5 pushes the value 5 onto the operand stack of the Java virtual machine. This value is then stored in the second local variable ( arg1 , with args as the first local variable). iload_1 pushes the value of the second local variable onto the operand stack, where it will serve as an argument to the called method.
在 main 方法中, iconst_5 指令将值 5 压入 JVM 的操作数堆栈( operand stack )。然后这个值随后存储第二个本地变量( arg1 的值存在第一个本地变量处)。 iload_1 指令将第二个本地变量的值再压入操作数堆栈,作为被调用方法的形参。
Then the method f is invoked using the invokestatic instruction. The argument value is popped from the stack, and is used to create a stack frame for the called method. This stack frame represents the local variables in f , with the method parameter ( arg1 ) as the first of the local variables.
然后方法 f 通过 invokestatic 指令调用。形参的值出栈,被用于为被调用的方法创建一个栈框架( stack frame )。这个栈框架表示所有 f 中的所有本地变量,而 arg1 实参将作为栈框架内的第一个本地变量。
What this means is that the parameters in a method are copies of the argument values passed to the method. If you modify a parameter, it has no effect on the caller. You are simply changing the copy's value in the stack frame that is used to hold local variables. There is no way to "get back" at the arguments in the calling method. So assigning to arg1 in f does not change arg1 in main . Also, the arg1 variables in f and in main are unrelated to each other, except that arg1 in f starts with a copy of the value of arg1 in main. The variables occupy different locations in memory, and the fact that they have the same name is irrelevant.
这里的的意思是形式参数作为实际参数的拷贝,被传入方法当中。如果你(在方法体内)修改了一个实际参数,它并不影响调用者,你只是修改了栈框架内的拷贝而已。不可能在调用方法中“取回”实参的值。因此在 f 中给 arg1 赋值不会改变 main 中的 arg1 ,而且这两个 arg1 毫无关联,除了 main 中的 arg1 是 f 中的 arg1 的一个拷贝之外。这两个变量存在内存的不同区域,事实上虽然它们有同样的名字,但是毫不相干。
By contrast, a pass-by-reference parameter is implemented by passing the memory address of the caller's argument to the called function. The argument address is copied into the parameter. The parameter contains an address that references the argument's memory location so that changes to the parameter actually change the argument value in the caller. In low-level terms, if you have the memory address of a variable, you can change the variable's value at will.
对比值传递,引用传递的参数是指传递调用者实参的内存地址给被调用的函数。实参地址拷贝给形参。形参指向了实参的内存区域,所以对形参的修改同样会修改到实参。从底层的角度来说,你可以任意修改变量的值,只要你有该变量的内存地址。
The discussion of argument passing is complicated by the fact that the term "reference" in pass-by-reference means something slightly different than the typical use of the term in Java programming. In Java, the term reference is used in the context of object references. When you pass an object reference to a method, you're not using pass-by-reference, but pass-by-value. In particular, a copy is made of the object reference argument value, and changes to the copy (through the parameter) have no effect in the caller. Let's look at a couple of examples to clarify this idea:
关于参数传递的讨论会复杂化,这是因为以上引用传递中的术语“引用”与 Java 编程中使用的(术语)存在微妙的区别。在 java 中,术语“引用”用于对象所有引用的上下文。当你给方法传递一个对象引用,你并不是使用引用传递,更像是值传递。尤其是,这样会拷贝一份实际参数的对象引用,(通过形参)对该拷贝的修改不会影响到调用者。让我们用以下两个例子来证明这个观点。
2
3 public int x;
4
5 A( int x) {
6 this .x = x;
7 }
8
9 public String toString() {
10 return Integer.toString(x);
11 }
12
13 }
14
15 public class CallDemo2 {
16
17 static void f(A arg1) {
18 arg1 = null ;
19 }
20
21 public static void main(String args[]) {
22 A arg1 = new A( 5 );
23 f(arg1);
24 System.out.println( " arg1 = " + arg1);
25 }
26
27 }
In this example, a reference to an A object is passed to f . Setting arg1 to null in f has no effect on the caller, just as in the previous example. The value 5 gets printed. The caller passes a copy of the object reference value ( arg1 ), not the memory address of arg1 . So the called method cannot get back at arg1 and change it.
在这个例子中, A 的引用传递给 f。 把 arg1 设置为 null 不影响调用者,就像前一个例子一样。程序会打印 5 。调用者传递一份对象引用( arg1 )的拷贝,而不是 arg1 的内存地址。所以调用方法无法取回到(调用者的) arg1 变量并修改它。
Here's another example:
2
3 public int x;
4
5 public A( int x) {
6 this .x = x;
7 }
8
9 public String toString() {
10 return Integer.toString(x);
11 }
12
13 }
14
15
16
17 public class CallDemo3 {
18
19 static void f(A arg1) {
20 arg1.x = 10 ;
21 }
22
23 public static void main(String args[]) {
24 A arg1 = new A( 5 );
25 f(arg1);
26 System.out.println( " arg1 = " + arg1);
27 }
28
29 }
What gets printed here is 10 . How can that be? You've already seen that there's no way to change the caller's version of arg1 in the called method. But this code shows that the object referenced by arg1 can be changed. Here, the calling method and the called method have an object in common, and both methods can change the object. In this example, the object reference ( arg1 ) is passed by value. Then a copy of it is made into the stack frame for f . But both the original and the copy are object references, and they point to a common object in memory that can be modified.
这个例子会打印 10 。为什么呢 ? 通过之前那个例子,你已经知道无法改变在调用方法中修改(实参) arg1 。但是这里的代码显示 arg1 能够被修改。这里调用方法和被调用方法有个共同的对象,两个方法都能修改这个对象。在这个例子中,对象的引用( arg1 )是值传递。他的一个拷贝被加入到 f 的栈框架。但是原来的和拷贝的对象都是对象引用,它们指向相同的内存区域中的对象,因此可以修改。
In Java programming, it's common to say things like "a String object is passed to method f " or "an array is passed to method g ." Technically speaking, objects and arrays are not passed. Instead, references or addresses to them are passed. For example, if you have a Java object containing 25 integer fields, and each field is 4 bytes, then the object is approximately 100 bytes long. But when you pass this object as an argument to a method, there is no actual copy of 100 bytes. Instead, a pointer, reference, or address of the object is passed. The same object is referenced in the caller and the called method. By contrast, in a language like C++, it's possible to pass either an actual object or a pointer to the object.
在 java 编程中,经常可以听到“一个 String 对象被传递到方法 f ”或者“一个数组被传到方法 g ”。从技术上来说,不是传递一些对象或数组,而是传递引用或地址。例如,如果你有一个 java 对象包含 25 个整型的属性,每个属性占 4 字节,那这个对象大约是占 100 字节。但是作为形式参数传递的时候,不会拷贝 100 字节。而是传递一个指针、引用或地址。这样调用者和被调用的方法都指向同一个对象。对比而言,与 C++ 类似的语言,它可以传递真实的对象,也可以传递该对象的指针。
What are the implications of pass-by-value? One is that when you pass objects or arrays, the calling method and the called method share the objects, and both can change the object. So you might want to employ defensive copying techniques, as described in the September 4, 2001 Tech Tip, "Making Defensive Copies of Objects "
那什么是隐含的值传递呢?其一是当你传递对象或数组,由调用方法和被调用方法共享,双方都可修改对象。因此你可能想请入保护性拷贝技术,就像 2001 年 9 月 4 日技术贴士“使用保护性拷贝技术。”
You can fix the case above, where the called method modifies an object, by making the class immutable. An immutable class is one whose instances cannot be modified. Here's how you to do this:
你可以 修正以上的例子,当被调用方法修改一个对象时,让这个类成为不可变的。一个不可变类是指其实例不可修改的类。这里教你怎样去定义它。
2
3 private final int x;
4
5 public A( int x) {
6 this .x = x;
7 }
8
9 public String toString() {
10 return Integer.toString(x);
11 }
12 }
13
14
15
16 public class CallDemo4 {
17
18 static void f(A arg1) {
19 // arg1.x = 10;
20 }
21
22 public static void main(String args[]) {
23 A arg1 = new A( 5 );
24 f(arg1);
25 System.out.println( " arg1 = " + arg1);
26
27 }
28
29 }
The printed result is 5 . Now uncomment the modification of A in f and recompile the program. Notice that it results in a compile error. You have made A immutable, so it can't be legally modified by f .
打印结果是 5 ,现在去掉 CallDemo4 中 f 方法内的注释和重新编译。注意它会编译出错。因为你已经让 A 不可变了,所以 f 不能合法修改它。
Another implication of pass-by-value is that you can't use method parameters to return multiple values from a method, unless you pass in a mutable object reference or array, and let the method modify the object. There are other ways of returning multiple values, such as returning an array from the method, or creating a specialized class and returning an instance of it.
另一个隐含的值传递是你不能利用方法的形参在一个方法中返回多个值,除非你传入一个不可变对象引用或数组,然后让方法修改该对象。还有另外的方式返回多个值,例如从方法中返回一个数组,或者创建一个特别定义的类的实例。
For more information about how arguments are passed to Java Methods, see Section 1.8.1, Invoking a Method, and section 2.6.4, Parameter Values, in "The Java Programming Language Third Edition " by Arnold, Gosling, and Holmes. Also see item 13, Favor immutability, and item 24, Make defensive copies when needed, in "Effective Java Programming Language Guide " by Joshua
想知道更多关于 Java 方法中的实际参数的传递的信息,请看 Arnold, Gosling, and Holmes 的《 The Java Programming Language Third Edition 》中的 1.8.1 节“ Invoking a Method ”和 2.6.4 节“ Parameter Values ”。还有 Joshua 的《 Effective Java Programming Language Guide 》 条款 13 “ Favor immutability ”和 24 “ Make defensive copies when needed ”。
发表评论
-
栈的简单应用--单词反转
2014-07-03 16:00 693我们知道栈是一种先进后出,也就是后进先出的数据 ... -
java实现简单的栈
2014-07-01 11:56 641栈--只允许访问第一个数据项即:最后插入的数据。最简单的一句 ... -
小心使用ArrayList和LinkedList
2014-06-30 16:32 784ArrayList内部是使用可増长数组实现的,所以是用ge ... -
有趣的Java算法(3)
2014-06-30 16:29 679给定两个排序后的数组A和B,其中A的末端有足够的空间容纳B ... -
有趣的Java算法(2)
2014-06-30 16:29 1055今天分享一个"将一个整数的每位数分解并按逆序输 ... -
有趣的Java算法
2014-06-20 17:00 746题目及源码分析: /* * 今天在BBS里面看到这 ... -
用java代码编写堆栈
2010-05-03 17:39 1232public class Stack { int[] ... -
几种读取属性文件的JAVA实现方式
2010-04-30 19:20 1176转载:http://darkranger.iteye.com/ ... -
Site
2010-04-30 19:20 965http://www.szikao.com/computer/ ... -
JAVA对XML的几种解析方式
2010-04-29 19:53 955对于XML介绍比较全面的还是IBM的专栏: ... -
集合与通用集合
2010-04-29 19:44 1428URL: http://www.ibm.com/develop ... -
HashMap 和TreeMap
2010-04-29 19:41 1275本文重点介绍HashMap。首先介绍一下什么是Map。在数组中 ... -
TreeMap和HashMap的问题
2010-04-29 19:39 2088在一次面试的过程 ... -
实现单用户登陆session先进先出(session踢出)
2010-04-29 19:33 9476首先在系统增加sessionListener 来监听sessi ... -
Java单态模式的实现
2010-04-29 19:23 15791.饿汉式:public class Sing ... -
请教java反射机制里可以调用私有方法吗?
2010-04-27 19:17 1625如题:请教java反射机制里可以调用私有方法吗? Metho ... -
利用java反射机制调用类的私有方法
2010-04-27 18:59 14151.将getInstance()方法设置为private ... -
String是原始数据类型还是引用数据类型
2010-04-26 19:22 1711请教各位高手,String是原始数据类型还是引用数据类型?谢谢 ... -
java中堆(heap)和堆栈(stack)有什么区别
2010-04-26 19:13 2193stack 和 heap 都是内存的 ... -
heap和stack有什么区别
2010-04-26 19:11 73121.heap是堆,stack是栈。 2.stack的空间由操 ...
相关推荐
### Java中的按值传递与按引用传递详解 #### 一、引言 在Java编程语言中,关于参数传递的方式一直存在两种观点:一种认为Java仅支持按值传递,另一种则指出Java同时支持按值传递和按引用传递。实际上,这两种观点...
在Java编程语言中,了解值传递和引用传递的概念至关重要,因为它们直接影响到函数参数的处理方式。下面将详细探讨这两个概念及其区别。 首先,我们来理解什么是值传递。在Java中,基本数据类型(如int、double、...
在Java编程语言中,函数参数的传递方式有两种:值传递和引用传递。理解这两种机制对于编写高效、无误的代码至关重要。以下是对这两种传递方式的详细解析。 首先,值传递是指函数调用时,实际参数的值被复制一份传给...
Java中传递对象时传递的并不是对象中的内容, 而是对象的地址。
Java 面向对象值传递和引用传递 Java 面向对象编程中,参数传递是非常重要的一个概念。参数传递有两种方式:值传递和引用传递。了解这两种方式的区别是非常重要的,因为它们对程序的执行结果产生了很大的影响。 值...
Java中的参数传递方式主要有两种:值传递和引用传递。理解这两种机制是编程中至关重要的,因为它们直接影响到函数内部如何改变或操作传入的数据。 **值传递**在Java中是基本数据类型(如int, double, char等)的...
在Java中,参数传递有两种方式:值传递和引用传递。这个“Java 值传递Visio资源”包含了几个Visio图形文件,帮助我们直观地理解这两种传递方式。 1. **值传递**: 当方法调用时,对于基本类型(如int, double, char...
13.java参数传递之引用传递.zip13.java参数传递之引用传递.zip13.java参数传递之引用传递.zip13.java参数传递之引用传递.zip13.java参数传递之引用传递.zip13.java参数传递之引用传递.zip13.java参数传递之引用传递....
标题“Java是值传递,传对象引用也是通过值”揭示了Java中参数传递的核心概念。Java总是以值传递方式进行,这意味着当你将一个变量作为参数传递给方法时,传递的是该变量所存储值的一个副本。然而,对于对象类型的...
本文将详细介绍值传递和引用传递的概念、用法以及它们之间的区别,并通过Java语言中的具体示例来加深理解。 #### 二、值传递 **值传递**是指在函数或方法调用时,传递给函数的实际参数的值被复制一份到形参,即形参...
Java值传递的一些理解 Java是一种基于对象的编程语言,它的内存分配机制是栈内存、堆内存和方法区内存三部分组成的。其中,栈内存主要存放函数中定义的基本类型变量和对象的引用,堆内存主要存放由new创建的对象...
Java中参数传递的方式有两种理解:值传递和引用传递,但这两种说法实际上是对同一种机制的不同角度的描述。下面将详细解释这两种理解方式。 首先,我们来看值传递的理解。在Java中,当一个对象作为参数传递给方法时...
java学习java语言的值传递和引用传递
详解java的值传递、地址传递、引用传递 java是一种面向对象的编程语言,它的参数传递机制是值传递的,而不是地址传递或引用传递。很多开发者对java的值传递和地址传递存在误解,认为java中的基本数据类型是值传递,...
当一个变量为一个参数传入方法内部的时候,会有两种不同的传递方式:值传递和引用传递。 值传递的特点:不管方法内部对传进去的参数作任何改变,也不会影响方法外部的变量的值 引用传递的特点:方法内部对传...
Java的参数传递方式实际上是一种特殊的"值传递",通常被称为"按引用传递对象的引用",这与C++等语言中的引用传递有所不同。以下是对这个主题的详细解释。 在Java中,所有的参数传递都是基于值的,但这涉及到一个...
我们先看一下值传递和引用传递的概念和区别 值传递:是指在调用函数时将实际参数复制一份传递到函数中,...我们通过例子理解一下Java的值传递: public static void main(String[] args) { int a = 10; int b = 20;
这里详细的说明了,java参数传递的过程,引用传递,值传递