又到互联网寒冬,所以强迫自己思考,写博客。
我记得原来有个面试题:到底创建了多少个String对象?因为在Java中,String比较特殊,还不是基本数据类型,但是呢,和普通的对象还不太一样。比如普通对象是这样用的
A a=new A();
但是String是这样用的
String str="zhang"
看到没,根本就不用new。但是这貌似有点让人犯难了。如果两个都是new的,我就能知道==的结果肯定是false。但是它不用new,这可怎么比较。
其实吧,String也可以new,而且两个new出来的也不一样,这点是和普通对象一样的,就像这样
String s6=new String("zhang");
String s7=new String("zhang");
System.out.println(s6==s7); // false
那么再来看一下不用new的情况
String s1 = "zhang";
String s2 = "zhang";
System.out.println(s1 == s2); // true
这个结果,如果大家知道常量池的话,也不会意外。"zhang"这个常量已经被创建在常量池了,所以不管被引用多少次,都是这一个常量。所以String是final的。
但是String可以拼接啊,我们可以这么用
String s1 = "zhang";
String s2 = "zh"+"ang";
System.out.println(s1 == s2); // true
这里的结果还是true,按说"zh"+"ang"是两个常量的结合,应该会有一个新生命诞生的【狗头】。其实看一下反编译的class文件,就知道效果是这样的
String s1 = "zhang";
String s2 = "zhang";
System.out.println(s1 == s2);
所以,谁在默默地付出,就不用我说了。 就是把.java-->.class文件的那个。
那么,换一种结合方式呢,jvm会继续优化吗
String s1 = "zhang";
String s2 = "zh"+new String("ang");
System.out.println(s1 == s2); // false
额,这个属实是没法优化啊,jvm刚编译完,它怎么可能知道new String("ang")的地址是在哪里,所以就按照常量池+一个新对象这样的处理方式赋值给了s2。所以结果只能是false。
但是,String提供了一个方法
String s1 = "zhang";
String s2 = "zh"+new String("ang");
System.out.println(s1 == s2.intern()); // true
intern这个方法的解释是这样的
调用intern方法时,如果由equals(object)方法确定的池中已经包含与此string对象相等的字符串,则返回池中的字符串。否则,将此String对象添加到池中,并返回对该String对象的引用。由此可见,对于任意两个字符串s和t,当且仅当s.equals(t)为真时,s.intern () == t.intern()为真
再底层的话,能力有限。。