近期连续看到有关数组的问题帖,其问题是将一个数组作为参数传递给某个method,并期望通过该method改变原先所引用之数组内容,但结果往往是原先的数组丝毫未动,小弟对JAVA reference机制偶有研究,希望以实际例子来说明java reference机制有别于C\C++首先该示例引用自本版帖子《如下的代码有什么问题?》,作者:wingofsea (翱翔的翼) ,为说明问题对实例稍做改动,如有冒犯之处还忘见量。其次要说明的是数组作为参数传递的问题乃是一个有关于java reference机制非常经典的问题,大多数初学JAVA的朋友在这样的问题上产生的困惑源自于C\C++的机制所带来的主观影响,因为在关于reference传递的问题上,JAVA 与 C\C++十分不一样。我们用实例来说明问题:示例代码1:
/**
 * 该类将说明将数组作为参数传递过程中,引用机制所起到的作用
 */
class testArray {
  /**
   * 打印数组的内容,并显示该数组的引用地址
   */
  static void printArray( int[] array ) {
    System.out.println( "The array's address: " + array );

    for( int i = 0; i < array.length; i++ )
      System.out.print( " " + array[i] );
    System.out.println();
  }
  
  /**
   * 企图通过该函数对所传递的数组进行改变
   */
  static void changeArray( int[] a1 ) {
    System.out.println( "array a1 in changeArray: " + a1 );
  
    int[] b = { 1, 2, 3 };
    System.out.println( "\nCreate array b..." );
    printArray( b );
    
    System.out.println( "\nafter a1 = b..." );
    a1 = b;
    System.out.println( "array a1's address : " + a1 + "\n");
  }
  
  /**
   * 主函数,实例化一个int array,并查看其在调用changeArray() method前
   * 与调用后内部数据的变化以及引用地址的变化。
   */
  public static void main( String[] args ) {
    System.out.println( "------------ Start Process ------------" );
    int[] a = { 3, 2, 1 };
    System.out.println( "Create array a... " );
    printArray( a );
    
    System.out.println( "\nCall changeArray methods.");
    changeArray( a );    // 期望通过引用传递改变数组a的内容
    
    System.out.println( "After call changeArray methods...(back main() method)" );
    System.out.println( "The array a is not changed..." );
    printArray( a );
  }
} /// @.@||~运行结果...
------------ Starting Process ------------
Create array a...
The array's address: [I@15601ea
  3 2 1Call changeArray() methods...
In changeArray(), array a1's address: [I@15601eaCreate array b...
The array's address: [I@197d257
  1 2 3after a1 = b...
a1's address: [I@197d257after call changeArray methods...(back main() method)
The array a is not changed...
The array's address: [I@15601ea
  3 2 1
总结:
这里我们可以很清楚的看到,虽然我们将数组a以引用传递的方式传递给了changeArray() method,并且在开始时changeArray() method中的int[] a1确实依然指向原先的对象,但是当我们改变了a1的指向,将其指向另一个新的数组b时,注意,注意,问题出现了,我们很自然的会和c\c++做参考,于是我们认为,由于此时a1(也就是方法内部的引用)发生了改变,同时就会引起
外部数组的改变,但是当我们回到main()函数时,数组a没有发生热和变化,我们可以看到a的引用依然指向原先的对象,这是为什么呢?是的,在JAVA中,数组依然是一个对象,对象就会以reference的形式传递,但是这个reference却是一个值传递,
我们先搞清楚
Tyep a = new Type();
这里a is a reference, 他指向一个Type Object,JAVA中突出了一个引用变量的概念,reference本身也是一种变量,所以reference本身以值传递的形式传送给某个method,
-----------------------------------------------------------------------------
重点
这时 changeArray()中的int[] a1 与 main()中的int[] a乃是两个同时引用同一个long array object的不同的reference,
------------------------------------------------------------------------------
当我们修改了changeArray()中的int[] a的指向时,并不会影响另一个reference的指向,这就是为什么没有发生改变的原因了。如果欲在此地同时改变两者就必须实际改变两者所引用的对象。
源代码如下:
class testArray {
  static void printArray( int[] array ) {
    System.out.println( "The array's address: " + array );

    for( int i = 0; i < array.length; i++ )
      System.out.print( " " + array[i] );
    System.out.println();
  }

  static void changeArray( int[] a1 ) {
    System.out.println( "array a1 in changeArray: " + a1 );
  
    int[] b = { 1, 2, 3 };
    System.out.println( "\nCreate array b..." );
    printArray( b );
    
    /* Don't do this,以下代码只是改变了reference a1 的指向,并位改变a1原先引用之对象的内部状态
     * System.out.println( "\nafter a1 = b..." );
     * a1 = b;
     * System.out.println( "array a1's address : " + a1 + "\n");
     */
    // 实际改变Object
    for( int i = 0; i < a1.length; i++ )
      a1[i] = b[i];
  }
  
  public static void main( String[] args ) {
    System.out.println( "------------ Start Process ------------" );
    int[] a = { 3, 2, 1 };
    System.out.println( "Create array a... " );
    printArray( a );
    
    System.out.println( "\nCall changeArray methods.");
    changeArray( a );    // 期望通过引用传递改变数组a的内容
    
    System.out.println( "After call changeArray methods...(back main() method)" );
    System.out.println( "The array a is not changed..." );
    printArray( a );
  }
} /// @.@||~运行结果...
------------ Starting Process ------------
Create array a...
The array's address: [I@15601ea
  3 2 1Call changeArray() methods...
In changeArray(), array a1's address: [I@15601eaCreate array b...
The array's address: [I@197d257
  1 2 3after call changeArray methods...(back main() method)
The array a is changed...
The array's address: [I@15601ea
  1 2 3我们可以看到main() method中的array a确实发生了改变。希望这个实例还能够说明一些JAVA reference的问题,希望能够对初学JAVA,或者是刚从C++跳转过来的朋友们有所帮助,本人也还是个JAVA初学者,上面的实例与说明难免会出现问题之处,望各位朋友多多包涵  ^ ^

解决方案 »

  1.   

    楼主说在关于reference传递的问题上,JAVA 与 C\C++十分不一样。楼主能不能说一说C++中的处理情况呢?
      

  2.   

    晕死,JAVA和C++完全一样的,只是JAVA没有提供直接修改“指针储存的内存区域”的方法
    //C++
    void fun(int * point){
        *point = 12345;//这里和JAVA完全相同
        int temp = 12345;
        point = &temp;//同上
        &point = 12345;
    }//JAVA
    void fun(int [] point){
       point[0] = 12345;
       point = new int[]{12345};   //JAVA是不支持直接修改指针储存的内存区域的
       //&point = 12345;
    }
      

  3.   

    TO:lxleaves(飘泊的叶子) 
        抱歉,本人并不同意您的说法。
        对于reference机制,其提供的操作便是如何籍由reference控制object,C++提供的操作直接支持reference对对象的直接控制,而JAVA中必须通过reference来间接控制object,但程序员本身却只可能操控reference。
        就实现机制本身而言,这就是二者最大的不同了,何为相同?@.@||~
      

  4.   

    千万别告诉我C中void fun(char * p){
       p = "test";
    }能改变实参
      

  5.   

    c++里&才叫引用。java里引用就相当c++里指针给个例子(内存泄漏暂不考虑)
    void changeArray1( int *a )
    {
        int b[] = { 1, 2, 3 };
        a = b;    //为什么修改不能影响外部,其实相当 int *temp=a1; temp=b;
    }void changeArray2(int* &a)
    {
      int *b = new int[3];
      b[0]=1;
      b[1]=2;
      b[2]=3;
      a = b;
    }void test(){
      int *a = new int[3];
      a[0] = 3;
      a[1] = 2;
      a[2] = 1;  printArray(a);
      changeArray1(a);
      printArray(a);
      changeArray2(a);
      printArray(a);
    }java里的只是相当与changeArray1, 而没用changeArray2这种形式
      

  6.   

    It is right what kingfish saied!And midthinker wrote the very good code as a java begainer.
      

  7.   

    我不知道对不对,我看的张孝祥java视频讲座基础篇里面类那一课,就说到拉这个问题
    不过那里面是对象,而不是这里的数组
      

  8.   

    呵呵,是这样的,张孝祥老师的视频讲座听说非常非常棒,但是在下至今无缘看一看,这个例子是在下自己做的,如果有问题还请指正,至于JAVA中array is a object,所以用object or array来说明这个问题其实是一样的。
        TO:lxleaves(飘泊的叶子)
        谢谢您给的建议,不过我完全赞同kingfish的观点,JAVA的引用十分接近于C/C++的指针概念,而非他们的引用概念。^^