未曾探索过的string连接符"+"

来源:互联网 发布:java实训日志 编辑:程序博客网 时间:2024/06/13 17:18

未曾探索过的string连接符”+”

1.来来来,有个string的面试题想找你谈谈,废话不多说,上菜!!

public class Test{    String a = "abc";    String b = "a" + a;}

这里创建了几个对象(常量池里面的对象也算)

最直观的办法还是看源码!这个怎么搞,不用怕,我们去分析编译过的class文件。这里需要用到javap命令

javac Test.javajavap -c Test

我们会得到如下内容

public static void main(java.lang.String[]);    Code:        //ldc(loadConstant) 将常量池中的"abc"放入栈顶       0: ldc           #2                  // String abc       //将常量池中"abc"的引用存到第一个局部变量a中       2: astore_1       //新建一个StringBuilder的对象       3: new           #3                  // class java/lang/StringBuilder       //复制栈顶的内容       6: dup       //调用StringBuilder构造器       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V       //将常量池中的"a"放入栈顶      10: ldc           #5                  // String a      //调用stringBuilder的append方法      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;      //装载第一个局部变量a的值      15: aload_1      //调用stringBuilder的append方法      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;      //将append的值变为string      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;      //将生成的string的引用存到第二个局部变量b中      22: astore_2      23: return}

可以看到创建的对象:

在常量池中存在 “abc” 和”a” 两个对象

在堆中创建了StringBuilder对象 ,最后调用toString方法产生一个String对象,里面存”aabc”

答案出来了。这里产生了4个对象。

2.现在再来看两句熟悉的代码

String a = "a";System.out.println(1+2+a); //Q1System.out.println(a+1+2); //Q2

分析:

​ Q1的输出? “12a” 还是 “3a”

​ Q2的输出? “a12” 还是”a3”

​ 其实这个题目对比起来看很容易明白,机智的你应该已经发现了端倪。编译器会优先做 “+”运算,当”+”连接的是整形时,先做加法运算,如果连接的是字符串,那么便是字符连接了。所以Q1的结果是”3a”,Q2是”a12”

3.第三个问题来了

String a = null ;Integer b = null;System.out.println(a); //Q1 "null"System.out.println(a + 2); //Q2 "null2"System.out.println(b + 2);//Q3 异常

分析:

​Q1是个选择题,选项有空字符串、null、抛异常,当时我就懵逼了。后来去看了源码,Q1代码会直接去找

public void println(String x) {        synchronized (this) {            print(x);            newLine();        }}然后public void print(String s) {        if (s == null) {            s = "null";        }        write(s);}

好的,找到答案了!是”null”
​那么Q2呢,Q2执行也会去找println(String x)这个方法,但是此时x已经是”null2”了,所以下面的if判断不会执行的,那么什么时候x变成了”null2”呢?
此时继续查看,会找到一个String.valueOf(Object)的静态方法。到这里大boss出来了,打断点你会发现,不管你执行什么代码,都会走这个方法,这里是是一个反射的源头,是通过这个,最后确定对象的类型,以及返回值。所以”a+2”先确认了返回字符串,然后再去拼接,看class文件你会看到括号里面的内容是(“”+object+2) 。
所以结果出来了,同理Q3也是先确认了返回的括号里面的类型是int,然后做加法运算,括号里面的内容是(((Integer)b).intValue() + 2),但是b对象是空,,所以抛出了null指针异常

另附上一些能帮助理解String的面试题

http://blog.csdn.net/chj97/article/details/6899598

0 0