在 Java 中值类型和引用类型是如何进行传递的,这个是我今天要谈论话题。

       关于这个话题,我的一个好友的推荐下看了一篇文章,这才使我有了写这篇文章的想法。这篇文章是《 Pass-by-Value Please (http://www.javaranch.com/campfire/StoryPassBy.jsp) ,顺便再向大家推荐一个网站,就是 http://www.javaranch.com ,一个很好的 Java 乐园。

       好了,回到正题吧~免得一下又跑远了~呵呵·

       关于值类型,我想大家都很清楚了,总的说来就是 Copy the value and give it to you

       请看如下代码:

 1 package blog.nichlas.article.j2se;
 2 
 3 import static java.lang.System.out;
 4 
 5 public class PassByValue {
 6     public static void testPassValue(){
 7         int a = 2 ;
 8         int b = a ;
 9         out.println("a= " + a ) ;
10         out.println("b= " + b ) ;
11         out.println("=============== the value has changed ===============");
12         a = 3 ;  // has change the value of a, but tht value of b is never be changed
13         out.println("a= " + a ) ;
14         out.println("b= " + b ) ;
15     }
16     
17     public static void main(String [] args){
18         out.println();
19         PassByValue.testPassValue();
20     }
21 }

结果如下:

a= 2

b= 2

=============== the value has changed ===============

a= 3

b= 2

 

这个例子很明显,不用过多的解释, a b 已经是两个独立的,互补相干的值。

 

下面进入我们今天的重点,关于引用类型。

我这里想借鉴一下我开篇提到的那篇文章,里面提到的杯子, I like the cap, do you?

在这里,我想打一个比方,把我们杯子里的引用 Reference 作一个类似,在操作系统里,有一个很重要的概念,那就是进程控制块,他是进程实体的一部分,是操作系统中最重要的记录型数据结构,他记录了操作系统所需的,用于描述进程的当前情况以及控制进程运行的全部信息。同样,引用也是如此,只是没有这么复杂罢了。引用里存放了 java object 的相关信息,以便让 JVM (Java Virtual Machine) 在堆中找到对象 (Java 对象全部在堆中 )

我们可以把这种情况想象成在一个杯子里放了一个类似于进程控制块的 reference ,下面来看如下代码:

 1 package blog.nichlas.article.j2se;
 2 
 3 import static java.lang.System.out;
 4 
 5 public class PassByValue {
 6     public static void testPassValue(){
 7         int a = 2 ;
 8         int b = a ;
 9         out.println("a= " + a ) ;
10         out.println("b= " + b ) ;
11         out.println("=============== the value has changed ===============");
12         a = 3 ;  // has change the value of a, but tht value of b is never be changed
13         out.println("a= " + a ) ;
14         out.println("b= " + b ) ;
15     }
16     
17     public static void testPassReference(){
18         ObjectForTest o1 = new ObjectForTest("Object one");
19         ObjectForTest o2 = o1;
20         out.println(o1.getInfo());
21         out.println(o2.getInfo());
22         out.println("=============== the value has changed ===============");
23         o1 = new ObjectForTest("Object two");
24         out.println(o1.getInfo());
25         out.println(o2.getInfo());
26     }
27     
28     public static void main(String [] args){
29         out.println();
30         PassByValue.testPassValue();
31         out.println();
32         PassByValue.testPassReference();
33     }
34 }
35 
36 class ObjectForTest{
37     String info ;
38         
39     public ObjectForTest(){
40         info = "default";
41     }
42         
43     public ObjectForTest(String initInfo){
44         info = initInfo ;
45     }
46         
47     public String getInfo(){
48         return info;
49     }
50         
51     public void setInfo(String changeInfo){
52         info = changeInfo;
53     }
54 }

运行结果是:

a= 2

b= 2

=============== the value has changed ===============

a= 3

b= 2

 

Object one

Object one

=============== the value has changed ===============

Object two

Object one

 

这里可以很明显的表示出其实所谓的 Reference 其实就跟值类型是很相似的,所以我们可以给 Reference 取一个名字“引用值”。

这里只是把 o1 的引用值拷贝了一份给 o2

 

 

不过这里要注意的就是虽然是引用值的拷贝,但他们却引用了同一个对象,任何一个对对象的改变都会,在另外一个引用上都可以显示的出来。
看如下的例子:

 1 package blog.nichlas.article.j2se;
 2 
 3 import static java.lang.System.out;
 4 
 5 public class PassByValue {
 6     public static void testPassValue(){
 7         int a = 2 ;
 8         int b = a ;
 9         out.println("a= " + a ) ;
10         out.println("b= " + b ) ;
11         out.println("=============== the value has changed ===============");
12         a = 3 ;  // has change the value of a, but tht value of b is never be changed
13         out.println("a= " + a ) ;
14         out.println("b= " + b ) ;
15     }
16     
17     public static void testPassReference(){
18         ObjectForTest o1 = new ObjectForTest("Object one");
19         ObjectForTest o2 = o1;
20         out.println(o1.getInfo());
21         out.println(o2.getInfo());
22         out.println("=============== the value has changed ===============");
23         o1 = new ObjectForTest("Object two");
24         out.println(o1.getInfo());
25         out.println(o2.getInfo());
26     }
27     
28     public static void testChangeObject(){
29         ObjectForTest o1 = new ObjectForTest("Object one");
30         ObjectForTest o2 = o1;
31         out.println(o1.getInfo());
32         out.println(o2.getInfo());
33         out.println("=============== the value has changed ===============");
34         o1.setInfo("Object Value changed!");
35         out.println(o1.getInfo());
36         out.println(o2.getInfo());
37     }
38     
39     public static void main(String [] args){
40         out.println();
41         PassByValue.testPassValue();
42         out.println();
43         PassByValue.testPassReference();
44         out.println();
45         PassByValue.testChangeObject();
46     }
47 }
48 
49 class ObjectForTest{
50     String info ;
51         
52     public ObjectForTest(){
53         info = "default";
54     }
55         
56     public ObjectForTest(String initInfo){
57         info = initInfo ;
58     }
59         
60     public String getInfo(){
61         return info;
62     }
63         
64     public void setInfo(String changeInfo){
65         info = changeInfo;
66     }
67 }

结果如下:

 

a= 2

b= 2

=============== the value has changed ===============

a= 3

b= 2

 

Object one

Object one

=============== the value has changed ===============

Object two

Object one

 

Object one

Object one

=============== the value has changed ===============

Object Value changed

Object Value changed

 

从这里可以看到, o1 对对象的改变体现在了 o2 上了,通过对 o2 的调用可以看出。

 

以上是我对这个问题的看法,希望大家可以给一点帮助。