A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

  1. public static void main(String[] args) {
  2.                 String s1 = "abc";
  3.                 String s2 = "xyz";
  4.                 show(s1, s2);
  5.                 System.out.println(s1 + "-----" + s2);
  6.         }

  7.         static void show(String s1, String s2) {
  8.                 s1 = s2 + s1 + "Q";
  9.                 s2 = "W" + s1;
  10.         }
复制代码


提问:这段代码的结果是什么,为什么不是abcxyzQ-----Wabcxyz?字符串不是对象吗,数组也是对象,如果对数组修改就会改变,可是本题中对字符串修改却。。。

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1 神马都是浮云

查看全部评分

13 个回复

倒序浏览
s1和s2分别为于两个方法中,是方法中的局部变量。只是同名,互不影响。showz中的s1和s2可以改成其他的你在试一下,一样可以。

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1 赞一个!

查看全部评分

回复 使用道具 举报
public static void main(String[] args) {
                String s1 = "abc";
                String s2 = "xyz";
                show(s1, s2);
                System.out.println(s1 + "-----" + s2);
        }

        static void show(String s1, String s2) {
                s1 = s2 + s1 + "Q";
                s2 = "W" + s1;
        }


字符串对象只能被初始化一次,而String s 声明一次只是将一个字符串地址出递给s
在main函数中,声明一次   
                String s1 = "abc";
                String s2 = "xyz";
也就是分别创建两个字符串对象"abc"和"xyz"将字符串对象的地址传递给s1和s2。
在调用方法show的时候,由于字符串对象只能被初始化一次,在调用show方法的语句
                s1 = s2 + s1 + "Q";                s2 = "W" + s1;的时候是再次创建一个字符串对象s2 + s1 + "Q",将此字符串对象的引用赋值给s1,创建一个字符串对象"W" + s1 ,将此字符串对象的引用赋值给s2,所以说,虽然main函数传递的字符串,字符串名字是相同,但是字符串对象只能被初始化一次,所以两个s1和s2的引用地址是不同的,在函数传递参数的时候说的也是传递地址值才能改变数据值,但是作为字符串对象,虽然可以传递地址值,但是每个字符串对象只能被初始化一次,所以,即便你传递的是地址值,在第二次改变值的时候,字符串对象变量会指向另一个地址的引用,你可以将String改为StringBuilder试一次,这样是可以的。


评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1 赞一个!

查看全部评分

回复 使用道具 举报
首先:s1="abc"和s2="xyz"会在堆内存和栈内存中开辟内存空间,见1号线
紧接着show(s1,s2)会在栈内存中为s1,s2开辟内存空间,指向堆内存的"abc"和"xyz",见2号线
随后,show方法中会进行计算,会在堆内存中在开辟内存空间进行s1=s2+s1+"Q", s2 = "W" + s1;的计算,所以s1="xyzabcQ",s2="WxyzabcQ",在show()方法中输出看一下就行,见3号线,,但是show()方法没有返回值.所以值不会改变.s1还是"abc",s2为"xyz"

搜狗截图20140527074940.png (21.82 KB, 下载次数: 55)

搜狗截图20140527074940.png

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1 赞一个!

查看全部评分

回复 使用道具 举报
不好意思啊,图片有点错误

搜狗截图20140527075934.png (147.12 KB, 下载次数: 57)

搜狗截图20140527075934.png
回复 使用道具 举报
真不好意思,发现还有点问题,真不是刷屏啊,请原谅

搜狗截图20140527080412.png (22.71 KB, 下载次数: 46)

搜狗截图20140527080412.png
回复 使用道具 举报
喜爱 高级黑马 2014-5-27 09:18:12
7#
字符串在内存当中是以常量存在的,不能修改其值,对它拼接字符串,实际上就是在内存当中又开辟新的空间,来存放拼接好的字符串。
回复 使用道具 举报
说的很透彻啊 ....
回复 使用道具 举报
李彦来 发表于 2014-5-27 07:57
首先:s1="abc"和s2="xyz"会在堆内存和栈内存中开辟内存空间,见1号线
紧接着show(s1,s2)会在栈内存中为s1,s2 ...

回答的很到位,赞一个
回复 使用道具 举报
public static void main(String[] args)
        {
                String s1 = "abc";
                String s2 = "xyz";
                show(s1, s2);
                System.out.println(s1 + "-----" + s2);
        }

        static void show(String s1, String s2)
        {
                s1 = s2 + s1 + "Q";
                s2 = "W" + s1;
                System.out.println(s1 + "-----" + s2);
        }
我感觉成成员变量和局部变量来解释比较好理解。main函数里的s1和s2局部变量,只在main函数内有效,show函数里的s1和s2,是在show函数内有效的局部变量。就相当于你在栈里开辟了二大块空间,二组s1和s2各指向堆内不同的字符串对象,互向不搭界
回复 使用道具 举报
其实本质问题就是,局部变量的作用域和就近原则,虽然String作为参数类型传递的时候和普通类一样是通过引用传递。但是我们在方法里面修改的是其副本。而不是原来地址指向的内存空间,且show方法内部的s1和s2都是方法内部重新创建的这个show方法内部的局部变量(参数可认为是局部变量),而不是main方法里面的s1和s2,他们不是同名,但是不同作用域。
可以为了方便理解可以把show里面的变量名修改,就容易理解了:
public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "xyz";
        show(s1, s2);
        System.out.println(s1 + "-----" + s2);
}
static void show(String s3, String s4) {
        s3 = s3 + s4 + "Q";//其实原来的的
        s4 = "W" + s3;
}
因为String类型比较特殊,涉及到String的不可变的特性(存放地址是常量池),为了方便理解可使用集合做参考
同样以集合来举例,调用show方法的时候,show方法内的al只是show方法内部的新建的局部变量和他外部的al只是同名,且指向的地址是同样的,如果show方法里面的操作,只是把其内部的局部变量al地址变为指向a2的地址,而没有修改原来参数传递的引用地址指向的值。所以外部输出al的时候其值不变。
但是调用show2方法的时候虽然a1同样是show2方法内部自己定义的局部变量,且和外部的a1同名(在栈内存中存放的地址不同,可以使用单步指向查看变量的地址)。但是他们指向同一个内存地址,且这个内存地址指向的内容和String不同是可以改变的。而直接对同一内存地址指向的内存空间内容进行修改,外部的a1指向的这一地址内容也发生改变
public static void main(String[] args) {   
        ArrayList al = new ArrayList();
        al.add("aa");
        al.add("bbb");
        al.add("ccc");
       show(al);
       Iterator<String> it = al.iterator();
      
       while(it.hasNext()){
               System.out.println(it.next());
       }
       System.out.println("----------------------------------------------");
      
       show2(al);
       Iterator<String> a = al.iterator();
       while(a.hasNext()){
               System.out.println(a.next());
       }
}

static void show(ArrayList al) {
        ArrayList a2 = new ArrayList();
    a2.add("222");
    a2.add("333");
    a2.add("444");
     al=a2;
}

static void show2(ArrayList al) {
    al.add("aaaa");
}

(不知道这样的解释可能明白)
回复 使用道具 举报
    再补充一句:你可以使用断点调试来查看各个变量的id地址,就可以轻易的明白各个变量虽同名但是他们地址是不同的,也就可以认为它们是不相关。只是要注意因为类的传递一般都是地址传递,要注意是改变变量的引用还是改变引用指向的地址值。
回复 使用道具 举报
昨天刚做了这道题,我觉得这道题的考点是利用show(s1,s2)来迷惑我们。
  System.out.println(s1,s2)这个输出语句要输出的是s1,s2这两个main()函数中的局部变量,而调用的方法show()方法在堆内存中确实是新建了两个对象,但是,它在栈内存中执行完毕后会弹栈,其结果并不影响main()函数的局部变量s1,s2.
回复 使用道具 举报
支持一下。。。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马