1.问题起源
public static void main(String[] args) {String s1 = "abc"; String s2 = "ab"; String s3 = "c"; String s4 = s2 + s3; String st0 = "helloworld"; String st1 = "helloworld"; String st2 = "hello" + "world"; System.out.println(st0 == st2); System.out.println(s1 == (s2 + s3)); System.out.println(s1 == s4);
}
答案全是false,为什么呢?
2.String pool
就像名字说的一样,String pool就是String对象池,或者说是集合。在java堆中特地开辟出来的空间存储String对象。java引入String pool这一个结构来优化String对象的定位和存储。
String类型是Java最常用的类型,而且非常消耗内存。与其建立多份的String对象不如共享相同的实例对象。
3.举栗子
3.1
public static void main(String[] args) {String s1 = "Cat"; String s2 = "Cat"; String s3 = new String("Cat"); System.out.println(s1 == s2); //true System.out.println(s1 == "s3); //false }</pre>
看图说话
众所周知,String对象是不可变的,值相同的String对象指向相同的实例。图中的Stringpool中值为“Cat”的String对象仅仅建立和存一次。当你再次使用String s2=“Cat”时 s2立刻指向了String pool中的“Cat”实例。这个只会在你使用硬编码,就是用字符串拼凑,一个一个字母输入的时候才会发生。s3使用了new建立了一个全新的String对象(“Cat”)它没有保存在String pool,而是保存在正常的堆中。
3.2
public static void main(String[] args) {String s1 = "Cat"; String s2 = "Ca"; s2 = s2 + "t"; System.out.println(s1 == s2); //false }</pre>
String是不可变的,当使用“+”连接两个String对象时底层调用的是StringBuilder,利用StringBuilder进行字符串的拼接。这样会返回有个全新的String实例,并保存在堆中,并不会放入String Pool中。不想要创建新的String对象,想利用String pool中的实例,可以利用String.intern()方法,返回String pool里面的一个已有的String对象
String s1 = "abc"; String s2= "abc";String s3 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1 == s3);s3 = s3.intern();
System.out.println(s1==s3);
4.证明
public static void main(String[ ] arg){String s1 = "abc"; String s2 = "ab"; String s3 = "c"; String s4 = s2 + s3; String st0 = "helloworld"; String st1 = "helloworld"; String st2 = "hello" + "world"; System.out.println(st0 == st2); System.out.println(s1 == (s2 + s3)); System.out.println(s1 == s4); }</pre>
回到一开始的代码块,利用javap命令查看编译后的二进制class文件,截图如下:
从常量池中可以看出类型为String的常量只有#2("abc'),#3("ab"),#4("c"),#9("helloworld"),而且有StringBuilder类的相关方法的调用,验证了String "+"操作利用了StringBuilder.append()方法。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于