string连接符”+”
1.来来来,有个string的面试题想找你谈谈,废话不多说,上菜!!
public class Test{
String a = "abc";
String b = "a" + a;
}
这里创建了几个对象(常量池里面的对象也算)
最直观的办法还是看源码!这个怎么搞,不用怕,我们去分析编译过的class文件。这里需要用到javap命令
javac Test.java
javap -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); //Q1
System.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的面试题