Java 引用传递

http://bbs.csdn.net/topics/390245117

我个人理解翻来覆去就两句话:

1、Java函数调用时,参数传递方式为值传递;
2、当该 参数类型为对象(Object)时,则所传递的值为对象的引用(也可理解为地址)。


如果你认为Java函数调用有指针传递或引用传递的话,你可以尝试编写这样一个函数来验证:
  public void swap(Object a, Object b);
效果就是调用后,主调函数的这两个对象互换即可。

比如主调函数是:
  String a = "A";
  String b = "B";
  swap(a, b);
  System.out.println(a); // 这里请输出 B
  System.out.println(b); // 这里请输出 A


当然,你别用反射之类的方式直接去修改常量池啥的招数。。。  


其实不能说Java "无引用传递", 而是Java针对非Primitive的数据类型"自动”进行了引用传递。
在C++里,假设有一个对象叫做foo, 那么在传递参数的时候:

C/C++ code
?
1
2
3
4
5
6
7
//函数fun
void  fun(Foo foo){
       ...
}
//传递参数foo给函数fun
fun(foo);

这时候直接这么写,C++编译器就直接是把对象foo按值拷贝传递给了函数fun, 如果要使用按引用传递,则必须写成:
C/C++ code
?
1
2
fun(&foo);

在Java里,由于在语法级别没有引用和指针的概念了,Java虚拟机强制规定,对于Primitive类型(int,float,double,boolean等基础数据类型),在传递参数时按值传递;对继承于Object的对象类型,在传递参数是“必须”使用引用传递,也就是说程序员没有选择的余地,即使想在Java中按值传递对象也是不可能的  


java中的引用类型概念

(2012-10-09 16:06:33)
1、什么是引用类型
 
      引用类型(reference type)指向一个对象,不是原始值,指向对象的变量是引用变量。
 
      在java里面除去基本数据类型的其它类型都是引用数据类型,自己定义的class类都是引用类型,可以像基本类型一样使用。

   
示例如下:

      public class MyDate {
              private int day = 8;
              private int month = 8;
              private int year = 2008;
              private MyDate(int day, int month, int year){...}
              public void print(){...}
      }
      public class TestMyDate {
              public static void main(String args[]) {
                  //这个today变量就是一个引用类型的变量
            MyDate today = new MyDate(23, 7, 2008);
              }
      }

2、引用类型的赋值

   
在java编程语言中,用类的一个类型声明的变量被指定为引用类型,这是因为它正在引用一个非原始类型,这对赋值具有重要的意义。如下代码:

      int x = 7;
      int y = x;
      String s = "Hello";
      String t = s;

      四个变量被创建:两个原始类型 int 和两个引用类型String。x的值是7,而这个值被复制到y;x和y是两个独立的变量且其中任何一个的进一步的变化都不对另外一个构成影响。至于变量s和t, 只有一个String对象存在,它包含了文本"Hello",s和t均引用这个单一个对象。

      java中的引用类型概念

    如果将变量t重新定义为t="World";则新的对象World被创建,而t引用这个对象。          
         
     java中的引用类型概念

3、按值传递和按引用传递的区别

      1)按值传递
     
    指的是在方法调用时,传递的参数是按值的拷贝传递。示例如下:

1.    public class TempTest {
2.             private void test1(int a) {
3.                     // 做点事情
4.                     a++;
5.             }
6.            
7.             public static void main(String args[]) {
8.                     TempTest t = new TempTest();
9.                     int a = 3;
10.                     t.test1(a);//这里传递的参数a就是按值传递。
11.                     System.out.printIn("main方法中的a===" + a);
12.               }
13.       }
   
    按值传递的重要特点:传递的是值的拷贝,也就是说传递后就互不相关了。第9行的a和第2行的a是两个变量,当改变第2行的a的值,第9行a的值是不变的,所以打印结果是3。

      main  方法中的a 为 3
      test1 方法中的a 为 4
     
      我们把第9行的a称之为实参,第2行的a称之为形参;对于基本数据类型,形参数据的改变,不影响实参的数据。

      2)按引用传递

      指的是在方法调用时,传递的参数是按引用进行传递,其实传递的是引用的地址,也就是变量所对应的内存空间的地址。

      示例如下:

1.    public class TempTest {
2.             private void test1(A a) {
3.                     a.age = 20;
4.                     System.out.printIn("test1方法中的age="+a.age);
5.             }
6.             public static void main(String args[]) {
7.                     TempTest t = new TempTest();
8.                     A a = new A();
9.                     a.age = 10;
10.                   t.test1(a);// 这里传递的参数a就是按引用传递
11.                         System.out.printIn("main方法中的age="+a.age);
12.               }
13.       }
14.     classA {
15.                public int age = 0;
16.        }  

    运行结果如下:test1方法中的age = 20  main方法中的age = 20

      按引用传递的重要特点:

      传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

    要想正确理解按引用传递的过程,就必须学会理解内存分配的过程,内存分配示意图可以辅助我们去理解这个过程。

    用上面的例子来进行分析:
   
      (1)、运行开始,运行第8行,创建了一个A的实例,内存分配示意图如下:

      main方法中的a 
   
      java中的引用类型概念

      (2)、运行第9行,修改了A实例里面的age的值,内存分配示意图如下:     
     
      main方法中的a 
     

       java中的引用类型概念
 
      (3)、运行第10行,是把main方法中的变量a所引用的内存空间地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽,但它们指向了同一个A实例。内存分配示意图如下:

    java中的引用类型概念

      (4)、运行第3行,为test1方法中的变量a指向A实例的age进行赋值,完成后形成新的内存示意图如下:

        java中的引用类型概念
        此时A实例的age值的变化是由test1方法引起的。
     
      (5)、运行第4行,根据此时的内存示意图,输出test1方法中的age=20
       
      (6)、运行第11行,根据此时的内存示意图,输出main方法中的age=20

      3)对上述例子的改变

      理解了上面的例子,可能有人会问,那么能不能让按照引用传递的值,相互不影响呢?就是test1方法里面的修改不影响到main方法里面的呢?

      方法是在test1方法里面新new一个实例就可以了。改变成下面的例子,其中第3行为新加的:

1.    public class TempTest {
2.             private void test1(A a) {
3.                     a = new A();// 新加的一行
4.                     a.age = 20;
5.                     System.out.printIn("test1方法中的age="+a.age);
6.             }
7.             public static void main(String args[]) {
8.                     TempTest t = new TempTest();
9.                     A a = new A();
10.                     a.age = 10;
11.                   t.test1(a);// 这里传递的参数a就是按引用传递
12.                         System.out.printIn("main方法中的age="+a.age);
13.               }
14.       }
15.     classA {
16.                public int age = 0;
17.        }  

      运行结果为:test1方法中的age=20  main方法中的age=10

      实现了按引用传递的值传递前与传递后互不影响,还是使用内存示意图来理解一下:

      (1)、运行开始,运行第9行,创建了一个A实例,内存分配示意图如下:

      java中的引用类型概念
     
      (2)、运行第10行,是修改A实例里面的age的值,运行后内存分配示意图如下:

      java中的引用类型概念
     
      (3)、运行第11行,是把mian方法中的变量a所引用的内存地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽。

      java中的引用类型概念

        (4)、运行第3行,为test1方法中的变量a重新生成了新的A实例,完成后形成的新的内存示意图如下:

    java中的引用类型概念

        (5)、运行第4行,为test1方法中的变量a指向的新的A实例的age进行赋值,完成后形成新的内存示意图如下:

    java中的引用类型概念

    注意:这个时候test1方法中的变量a的age被改变,而main方法中的a变量是没有改变的。

        (6)、运行第5行,根据此时的内存示意图,输出test1方法中的age=20

        (7)、运行第12行,根据此时的内存示意图,输出main方法中的age=10

      说明:

      (1)、“在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。

      (2)、在Java里面只有基本类型和按照下面这种定义方式的String是按值传递,其它的都是按引用传递。就是直接使用双引号定义的字符串方式:String str = "Java快车";

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值