黑马程序员技术交流社区

标题: Java传的到底是值还是引用 [打印本页]

作者: 不抛弃不放弃    时间: 2013-11-10 12:44
标题: Java传的到底是值还是引用
找高手!  我要找高手!。为什么经过方法处理后,得到的结果不一样?代码如下:
        public class Test{
                 public  void addInt(int i){
                             i+=1;
                        }
                  public void addStr(String str)  {  str+="111" };
                 public  void addList(List<String> strList){ strList.add("List111");}

              public static void main(String []args){

                 int i=0;
               String str="s";
             List<String> strList= new ArrayList<String>();
               Test t= new Test();
           t.addInt(i);
             t.addStr(str);
            t.addList(strList);
           System.out.println(i);             //输出0,为什么不是1
            System.out.println(str);          // 输出s;为什么不是s111
           System.out.println(strList.get(0));     //输出List111,为什么就是这个可以
               }

   }

     为什么int类型和String类型的变量经过方法处理后值没变,而List类型的变量值却变了?

作者: 零下五度的水    时间: 2013-11-10 13:10
这个跟Java语言无关,每种语言都是这么定义的,
对于方法的参数
栈中值的改变无效,堆中值的改变保留
int 是基本类型,值直接存放在栈中
String 是final类,值改变会新建一个对象,相当于重新在栈中赋值(指向的堆地址改变了)
List 是类,只会改变堆中的信息,所以改动被保留
作者: 文涛    时间: 2013-11-10 13:14
java准确的说是传值,不是传引用。
  java的传值分两种情况,一是常规数据类型如int,double,二是对象,就如你的test。对于int等这种普通数据类型当然就跟c一样,只是简单的传值,所以你调用 t.addInt(i);,只是变量i的值被传递进方法,只是传递了一个副本,所以addIn方法里面的i和外部的i不是一个变量,是两个独立的变量,所以操作与外部定于的i无关。所以输出还是0.
  对于 t.addStr(str);这个方法则稍稍不同,str是一个字符串对象,所以传值不是简单的传递一个副本那么简单,而是传递了指向字符串"s"的引用(指针)给函数addStr(String str),所以,在addStr中的str是一个新的指针,指向了"s",而字符串是常量,是不允许更改的,它们存放在常量区,于是当你做 str+="111"运算的时候,会在内存的常量区再开辟一个空间存放“s111”,并让str指向这个字符串,但是这个str是addStr的局部变量,是另一个指针,与原本的字符串指针没有关系,因此输出的时候还是输出了“s”
  最后一个t.addList(strList);也有所不同,他跟String一样是对象,传递时也是传递引用即是指针给方法,而list是允许动态添加数据的,于是你在addList方法里面使用同样指向该strList的指针来操作了真正的strList对象,从而使得方法外部的strList被操作,所以打印时就是List111。
作者: 魏-玉-彪    时间: 2013-11-10 13:29
本帖最后由 魏-玉-彪 于 2013-11-10 13:40 编辑


  1. /**
  2. *
  3. *     为什么int类型和String类型的变量经过方法处理后值没变,而List类型的变量值却变了?
  4. */

  5. public class Test {
  6.         
  7.         public int addInt(int i) {
  8.            return        i += 1;
  9.         }
  10.         
  11.         //public void addInt(int i) {             //首先这里没有返回值
  12.         //        i += 1;
  13.         //}

  14.         public void addStr(String str) {
  15.                
  16.                 str+="111"; };

  17.         public void addList(List<String> strList) {
  18.                 strList.add("List111");
  19.         }

  20.         public static void main(String[] args) {

  21.                 int i = 0;
  22.                 String str = "s";
  23.                
  24.                 List <String> strList = new ArrayList<String>();
  25.                 Test t = new Test();

  26.                 //t.addInt(i);
  27.                 //t.addStr(str);     因为没有反回值   所以这里是多余的,
  28.                

  29. //假如有返回值,需要调用 对象的方法才有.
  30.                 System.out.println(        t.addInt(i));         

  31.                 System.out.println(i); // 输出0,为什么不是1   
  32. System.out.println(str); // 输出s;为什么不是s111

  33.   /*事实上,这里输出的是main方法中的变量
  34. 因为对象中没有返回值,所以值没有变.而且字符串对象一经创建就不会改变,
  35. 除非引用地址改变,而这里的引用地址并没有改变
  36. */
  37.                
  38. t.addList(strList);  
  39.                 System.out.println(strList.get(0)); // 输出List111,为什么就是这个可以

  40. //这里ArrayList虽然和String都是引用类型数据,但不同的时,对其操作不会产生新的对象,所以
  41. //处理的是一个对象,不用返回值,仍然影响了ArrayList对象本身.
  42.         }

  43. }
复制代码

字符串一经创建就不会改变
举例 String s= "abc";               s的地址是 0X000002;  
s=s+"def";                     对不起,这时s的地址指向了新的地址也许是0X007782而 不再是 0X000002
s+"def"   的意思是,  从s地址0X000002找一个 "abc",从"def"  的地址假如是0X999008 找一个"def"  这时,
s地址仍是 0X000002;  "def"地址仍是0X999008
ArrayList  不同,假如ArrayList as其地址是 0X8888,
as.add("List111") 后,
as其地址仍然是是 0X8888, 所以,不用返回值,仍然改变了其中的内容,而地址没变





作者: dolphin    时间: 2013-11-10 15:03
你写得这3个,你在它们的方法中,写个输出方法,所有都会如你所想的那样输出。但是你在另一个方法中调用的时候,区别就不一样。
值传递,针对于基本类型,它的最初值始终不变,你看成是要其他方法调用此方法时,保持类型一致就行
引用传递,针对于引用类型,它的值是看情况,如果引用地址被操作,则最初值就跟着变化。但是它有一个特例,就是String。
String被定义为final类型的,再传参的时候,和值传递等效。




作者: 月生春    时间: 2013-11-10 15:21
因为Sting类型一旦建立就会在堆内存开辟空间,是不能改变的
作者: hurryup    时间: 2013-11-10 16:29
一句话,方法中有的,就使用方法中的,没有的则使用被调用方法的。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2