据本人之拙见,java传值都是传数据的副本,修改其值不会影响原来的值,传地址会影响原来的值,头疼之代码如下:public class Test {   public void change(int a) {
       a = a + 1;
   }
   public void change2(int[] a, int[] b) {
       a = b;
   }   public void iter(int[] a) {
       for(int i : a) {
          System.out.print(i + " ");
       }
   }
   public static void main(String[] aaaaaa) {
          int num = 1;
          int a[] = {1,1,1};
          int b[] = {2,2,2};
          Test t = new Test();
          t.change(num);
          t.change2(a,b);
          System.out.print(num);  /// num = 1
          t.iter(a);  //  为什么还是 “1 1 1”???  难道数组不是引用类型的吗?不是传地址的?????   }
}最后弱弱的问下各位高手,定义一个final类型的数组,为什么在程序中,其中的每个元素的值都能被改变?常量也能被改变吗?

解决方案 »

  1.   

    http://topic.csdn.net/u/20080610/11/54f77de8-3fbf-44ae-87d6-a5a9de2715dd.html
      

  2.   

    定义一个final类型的数组, 为什么在程序中,其中的每个元素的值都能被改变
    例如final int[] array = new int[10]; // array只是一个4字节的内存地址值, 并没有占用10个int的内存空间.
    注意, 把array传给一个函数的时候, 传递的是array存储的内存地址值的副本, 并不是他所指向的10个int的那一段内存的副本.所以当你给array赋值时, 因为他是final的, 编译会报错, 但是给array[1]等赋值的时候, 是给他指向的内存赋值, 并不是array本身, 所以没问题.
      

  3.   

    首先谢谢大伙,final那个弄明白了,但是那个数组传地址还是没明白;在函数参数中传递的是数组的引用地址,在函数中我改变了a的指向,按说a应该指向b数组在内存中那段数据区,可是为什么a的指向还是没有发生变化?
      

  4.   

    理顺清楚就不会头疼了。
    关于 Java 中对象的复制
      

  5.   

    传地址没错 数组的本质的确是类int[] b=(int[])object 可行!但是你的方法是第三方调用,已经超越了类模型的安全限定!如果都能交换成功,那Java安全何在!如果你把int[] a 写进类模型,你看看!一定会成功!如果超过安全限定,那么方法就是另一个指针副本,但是值却被COPY进方法区!你修改的是方法区的值,此时要返回值,重新赋予就可以了。开始学java的时候认为方法属于类,时间久了,方法确是一个独立的行为。方法也是类。如下代码方便理解。   public void change2(List a, List b) {         
      System.out.println("交换前的a-HASH"+a.hashCode());
      System.out.println("交换前的b-HASH"+b.hashCode());
      a = b;
      System.out.println("交换后的a-HASH"+a.hashCode());
      System.out.println("交换后的b-HASH"+b.hashCode());
      System.out.println(a);
      } 今天又有点晕,胡说八道在所难免。
      

  6.   

    只是在t.change2(a,b); 方法内赋值给数组a 但是Java也有作用域啊,而每个花括号就是一个对象的作用域,你在那个方法里面改变了a 的值,过了这个}后就不起作用了
      

  7.   

    这个只是作用域起的作用啊,干吗整大惊小怪内。NUM 和A[]  都不是类得成员变量。 方法里执行就是执行一次并不会给NUM A[] 进行赋值 你在你那个方法里输出就是你想要得 如果方法以外的话就是main里定义得初始状态
      

  8.   

    基本数据类型的值传递理论是没有问题的。public class Test {
      public void change(int a) {
        a = a + 1;
      }  public static void main(String[] args) {
        int num = 1;
        Test t = new Test();
        t.change(num);
        System.out.print(num);  // num = 1
      } 
    }
    记住!引用类型的参数传递也是传递。
    问题在于引用类型变量的值是什么?是对象的内存地址。public class Test {
      public void change2(int[] a, int[] b) {
        // 此时的局部变量a与主函数中的变量a是两个变量
        // 两个变量的值相同(指向同一个对象的地址)
        a = b; 
        // 此时只改变了局部变量a的值,主函数变量a的值没有改变。
      }   public static void main(String[] args) {
        int a[] = {1,1,1};
        int b[] = {2,2,2}; 
        Test t = new Test();
        t.change2(a, b);
        t.iter(a);  //  为什么还是 “1 1 1”???  因为引用类型也是值传递!
      } 
      public void iter(int[] a) {
        for(int i : a) {
          System.out.print(i + " ");
        }
      } 
    }
    我们可以在函数内部修改对象的内容,而不是变量的值。public class Test {
      public void change3(int[] a) {
        // 此时的局部变量a与主函数中的变量a是两个变量
        // 两个变量的值相同(指向同一个对象的地址)
        a[0] = 2; 
        // 此时改变的是对象的内容。
        // 局部变量a的值没有改变,仍然与主函数变量a的值相同。
      }   public static void main(String[] args) {
        int a[] = {1,1,1};
        Test t = new Test();
        t.change2(a);
        t.iter(a);  //  结果为“2 1 1”
      } 
      public void iter(int[] a) {
        for(int i : a) {
          System.out.print(i + " ");
        }
      } 
    }
    关键字final限制的是变量的值,而不是对象的内容。public class Test {
      public static void main(String[] args) {
        final int a[] = {1,1,1};
        a = {2,2,2}; // 该语句在编译时报错,因为此时变量a的值不能改变。
        a[0] = 2;  // 可以执行,因为改变的是对象的内容,与变量的值无关。
      } 
    }
    总之,这类让人头疼的问题本质在于 变量的值与对象的内容 两者之间的区别。
    看看Java中的数据比较(再谈==与equals的区别)一文,希望对楼主有所帮助。
      

  9.   

    "只是在t.change2(a,b); 方法内赋值给数组a 但是Java也有作用域啊,而每个花括号就是一个对象的作用域,你在那个方法里面改变了a 的值,过了这个}后就不起作用了"如果我这么写:class Test1 { public void change(StringBuffer s) {
    s.append("b");
    }

    public static void main(String[] args) {
    StringBuffer s = new StringBuffer("a");
    new Test1().change(s);
    System.out.println(s.toString()); // 结果是 ab
    }
    }这个应该是标准的传地址吧....如果参数有作用域的话,那么这个s是不应该改变的啊.....
      

  10.   

    请楼主深刻体会变量的值与对象的内容两个概念。public void change(StringBuffer s) {
      s.append("b"); // 此处改变的是对象的内容,不是变量的值。
    }
      

  11.   

    哦,看完你那篇博客好像理解了很多...现在又发现了一个问题class Test1 {public int n = 2;

    public Test1(int a) {
    this.n = a;
    }
    public void add(int nn) {
    this.n = nn;
    }
    public static void main(String[] args) {
    int n = 444;
    System.out.println(new Test1(22).n); // 结果成员变量n的值改变了
    new Test1(22).add(n);//结果成员变量n的值不能改变,这又是为什么呢?
    }
      

  12.   

    public class Test {
        public int n = 2;    public Test(int a) {
            this.n = a;
        }    public void add(int nn) {
            this.n = nn;
        }    public static void main(String[] args) {
            int n = 444;
            Test t1 = new Test(22);
            System.out.println(t1.n); // 22        Test t2 = new Test(22);
            t2.add(n);
            System.out.println(t2.n); // 444
        }
    }
    问题提得莫名其妙!
      

  13.   

    public class Test {    public void change(int a) { 
          a = a + 1; 
      } 
      public void change2(int[] a, int[] b) { 
          a[0]=100;
      }    public void iter(int[] a) { 
          for(int i : a) { 
              System.out.println(i + " "); 
          } 
      } 
      public static void main(String[] aaaaaa) { 
              int num = 1; 
              int a[] = {1,1,1}; 
              int b[] = {2,2,2}; 
              Test t = new Test(); 
              t.change(num); 
              t.change2(a,b); 
              System.out.println(num);  /// num = 1 
              t.iter(a);  //  为什么还是 “1 1 1”???  难道数组不是引用类型的吗?不是传地址的?????    } 
    } 输出的是:100 1 1
    数组是OBJECT,其实ab两个OBJECT还是那两个OBJECT,但是如果这个两对像的中的元素发生了变化..就会有变化. a = b; 
    只是作为函数内的参数..与你在主函数中初始化的对像是无关的...
      

  14.   

    关于这个问题提的我自己都很莫名其妙:
    class Test1 { public int n = 2; public Test1(int a) { 
    this.n = a; 

    public void add(int nn) { 
    this.n = nn; 

    public static void main(String[] args) { 
    int n = 444; 
    System.out.println(new Test1(22).n); // 结果成员变量n的值改变了 
    new Test1(22).add(n);//结果成员变量n的值不能改变,这又是为什么呢? 
    }可是刚才怎么都不能改变成员变量的值了,不知道是不是jdk的问题,重启了下电脑,再试发现可行了..呵呵
    谢谢各位了!!!
      

  15.   

    把你的代码修改了一下:package test;public class Test { public void change(int a) {
    a = a + 1;
    } public void change2(int[] a, int[] b) {
    a[0] = 2;
    a = b;
    a[0] = 1;
    } public void iter(int[] a) {
    for (int i : a) {
    System.out.print(i + " ");
    }
    } public static void main(String[] aaaaaa) {
    int num = 1;
    int a[] = { 1, 1, 1 };
    int b[] = { 2, 2, 2 };
    Test t = new Test();
    t.change(num);
    t.change2(a, b);
    System.out.println(num); // / num = 1
    t.iter(a); // 为什么还是 “1 1 1”??? 难道数组不是引用类型的吗?不是传地址的?????
    System.out.println();
    t.iter(b);
    }}
    java传值是对的,不过应该这样子理解:简单类型直接复制一个新的值,而对象则是复制了传递对象的地址传递过去。
    其实所有的对象(完整地说是对象实例引用变量)可以理解为一个简单变量,只不过这个变量中存的是实例内容地址,而简单类型直接就是存的相应的数据。
    针对这里,main中的a和change2方法的a是具有相同的对象实例引用地址的两个值变量,所以,这个时候a[0] = 2;改变的就是main中a引用的实例,两个内容都会被改变,因为两个变量存的地址相同;但是当在方法中a=b时,方法中a变量的值,就是引用地址变为了b得,但是main中的a变量的值所引用实例地址并没有改变。
    可以这样子简单的理解,对象(变量)可以理解为指针,指针只是存储了实例的地址,是一个简单对象,所以,当你把它等于另外一个对象,只是指针变化了。而java中传值,所以,不会影响原来的指针指向的地址。
      

  16.   

    假设你的change2方法改变成了 public void change2(int[] a1, int[] b1) {执行了t.change2(a, b);以后,a和b把自己的引用赋给了形参a1和b1,这样a和a1指向同一个地址,b和b1指向了同一个地址。在chang2方法内部,你把b1的指向赋给了a1,这样,指向信息又变成了:a指向原来的地址,b和b1和a1指向了同一个地址,a和b的指向并没有改变。所以最后你打印a数据的值,当然没有任何变化。
      

  17.   

    就是一个变量作用域的问题,LZ你把你2个函数的参数a,b修改成 x,y再看看就明白了
      

  18.   

    1.java中只有值传递 没有引用传递
    2.传地址本质也是值传递
    3.虽然java中一直踢到reference,但是其实java中的变量(除了原始类型)都是指针,只不过美化过了,不能直接改变地址。4。所以你可以考虑你把指针传过去当然能改变其中内容。
    5。final 参数主要是指该参数的值不能被修改。如果你穿过的是地址,只是这个参数中的这个地址不能被修改。但是这个地址指向的内容是可以修改的。
      

  19.   

    呵呵,初看代码,我也被小晕了下......关键是你的2个change方法都没有返回值啊.
      

  20.   


    在补充一下:   从oo出发,这个Test类,设计的这2个change方法一点意义和用处都没有,当然除了让我犯了下晕.....
    鄙视这种所谓的"题目"......
      

  21.   

    是常量还是引用  只要看定义对象时有没有new关键字,final数组用到了new表示在内存中实际为它分配了空间,int型数组每用到new,相当于还是常量
      

  22.   

    呵呵 类似c中的 **传值Fun(**a,**b){*a=*b}
      

  23.   

    change 和change2方法没有返回值,main函数中定义的num=1和int a[] = { 1, 1, 1 };值都没有改变。修改如下:
    public class Test { public int change(int a) {
    return a + 1;
    } public int[] change2(int[] a, int[] b) {
    return b;
    } public void iter(int[] a) {
    for (int i : a) {
    System.out.print(i + " ");
    }
    } public static void main(String[] aaaaaa) {
    int num = 1;
    int a[] = { 1, 1, 1 };
    int b[] = { 2, 2, 2 };
    Test t = new Test();
    num=t.change(num);
    a=t.change2(a, b);
    System.out.println(num); /// num = 1
    t.iter(a); //  为什么还是 “1 1 1”???  难道数组不是引用类型的吗?不是传地址的????? }
    }
      

  24.   

    个人感觉:public void change2(int[] a, int[] b)里面的参数数组a、b和main里的a、b数组是两个不同存储空间。以下把参数a、b数组成为参_a、参_b,把main里的数组a、b称为main_a、main_b。main里调用t.change2(a,b)时: 
    参_a、参_b作为局部变量被创建。把main_a、main_b所持有的两个数组的引用(指针)传给参_a、参_b。这之后,main_a和参_a指向同一数组,main_b和参_b指向同一数组。在change2里a = b; 
    把参_b赋给参_a。此时,参_a、参_b、main_b指向同一数组。当离开change2函数时,参_a、参_b作为局部变量都被销毁。在整个过程当中,main_a、main_b始终指向程序开始时给它们初始化的数组,因此不会发生任何改变。
      

  25.   

    捡重点说:这里有四个int类型的一维数组的引用
    main_a, main_b, change2_a, change2_b;
    程序运行时,main_a, main_b被初始化
    main_a 指向堆内存中的一片区域,存储内容为{1, 1, 1};
    main_b 指向堆内存中的另外一片区域,存储内容为{2, 2, 2};
    在调用change2(int[] a, int[] b)时
    change2_a指向main_a指向的{1, 1, 1}, change2_b指向main_b指向的{2, 2, 2};
    a = b;语句操作的结果是change2_a指向了change2_b指向的main_b指向的{2, 2, 2};
    如果此时调用new Test().iter(a),将打印出{2, 2 ,2}的内容,前提是LZ的iter(int[] a)方法要做修改<<<System.out.print(a[i] + " ">>>
    change2(int[] a, int[]b)方法运行结束,change2_a, change2_b局部变量被释放
    而main_a所指向内容并没有发生改变,依然是{1, 1, 1};
    另外LZ所写iter方法中并不是打印数组内容,打印的是数组index,System.out.print(a[i] + " ");
    完毕
      

  26.   

    public class Test {   public void change(int a) { 
          a = a + 1; 
      } 
      public Int[] change2(int[] a, int[] b) { 
          a = b; 
         return a;
      }   public void iter(int[] a) { 
          for(int i : a) { 
              System.out.print(i + " "); 
          } 
      } 
      public static void main(String[] aaaaaa) { 
              int num = 1; 
              int a[] = {1,1,1}; 
              int b[] = {2,2,2}; 
              Test t = new Test(); 
              t.change(num); 
              a[]=t.change2(a,b); 
              System.out.print(num);  /// num = 1 
              t.iter(a);    } 
    } 这样就是22222了
      

  27.   

     public void change2(int[] a, int[] b) { 
      for(int i=0;i<a.length;i++){
      a[i]=b[i];
      }
      } 
    就是222
      

  28.   

    数组是传的引用,正因为传的引用,所以打印出的a的值才没有变化,因为执行change2与主函数中的a跟本没关系啊,主函数的a一直指向{1,1,1}
      

  29.   

    public class Test {
    public static void change(int[] a, int[] b) {
    a = b;
    for(int i:a) {
    System.out.println(i);
    }
    }
    public static void main(String[] args) {
    int a[] = {1, 1, 1};
    int b[] = {3, 3, 3};
    change(a, b);
    for(int i: a) {
    System.out.println(i);
    }
    }}
    我把你的代码改成这样,输出结果是:333111。可见是传值,不是传地址嘛。编译原理有个Display构造表还特别讲到这个呢。