网上关于String和文章太多了,很多一知半解的作者都在误导大众,本人也是深受其害啊,直到今天看了这篇文章(http://www.wtoutiao.com/a/1023451.html),才拨开层层迷雾,发现JDK6和7的实现还不一样呢,发帖纪录一下。
1 一定要注意String s1=new String("c"); 2 这句话的意思是,编译期在常量池就生成了字符串"c",。运行时在堆也生成了一个string对象"c",注意这两个字符串没有丝毫的关系。当执行s1.intern()时,编译器去常量池查找,发现常量池已经存在了字符串"c",所以什么都不干。这句话不会导致任何结果。可是如果是 String s2=s1.intern();s2会直接指向常量池中的这个字符串。 3 只要是有new关键字即new String("c");都会在堆里面生成一个新的"c",这个"c"个和常量池没有关系。
1 如果常量池中本来就有这个字符串,则调用intern方法,不会有任何后果,相当于没调用。 2 只有当常量池中不含有这个字符串的时候,调用intern方法才会导致常量池和堆产生关系,即在常量池中新建一个“字符串常量”,确切的说这个“字符串常量”不是字符串,只是指向字符串的引用,真正的字符串在堆里面。
1 重要的内容再次强调一下: 2 s.intern()方法作用:如果常量池中存在字符串s , 就会直接返回 字符串 s 在常量池中的地址, 如果常量池中没有字符串s , 会将 堆中的字符串s 的地址放入常量池中, 然后返回的是堆中字符串s 的地址,这种情况下,常量池中存储的其实不是真正的字符串,而是指向堆中真正字符串的引用。
1 看下面的代码: (编译器在常量池已经生成了三个字符串,分别是a、b、ab,下面详细分析运行时在对中新创建的字符串对象) 2 String s1=new String("a")+new String("b"); 3 //两个new分别在对中产生a、b两个字符串,加号导致的结果是产生一个StringBuffer, 4 初始内容是a,append(b),然后调用toString方法,产生String对象"ab" 5 String s2=s1.intern(); 6 //检查常量池,因为常量池中不存咋字符串"ab",所以把把堆中的字符串"ab"的引用放入常量池, 7 注意常量池中存储的不是真实的string对象,而是一个引用,真正的string对象在堆中。 8 String s3=new String("a")+new String("b");//s1同理 9 String s4=s3.intern();//核心就是这里,s4其实指向的是s1,理解了这里就算是真正理解了jdk7的常量池了。(区别于jdk6) 10 11 System.out.println(s2==s1); 12 System.out.println(s4==s3); 13 System.out.println(s4==s2); 14 结果: 15 true 16 false 17 true
最后还是要说一句,网上各路大神都自视对java的虚拟机、常量池很了解,其实都是在误人误己,特别是这篇文章(http://www.iteye.com/topic/522167),现在才发现在堆里面根本没有什么所谓的“拘留字符串区”。
以上是我的一些理解,如果有什么错误,欢迎同行批评指正。
时间: 2024-12-24 06:17:09