String的不解-String对象在内存中的位置

String的疑惑-String对象在内存中的位置
“String倒底奇特在哪里?”关于这个问题本来想放过它的,但听说java面试经常考它,而且博友又给我提了不少珍贵的意见,所以准备在尽点力。

废话到此,下面正式开始



1.请看下面这幅图片:



         是否觉得奇怪,在1处为true,2处为false!对java有所了解都知道“s1==s2"比较的并非它们在的值(那时该用:s1.equals(s2)),而是比较他们在内存中的地址!难道s1,s2引用的是内存中的同一个数据,呵呵,正是如此!

        由于String对象在编程中使用的极为平凡,故而随着程序的增长,势必造成String常量占有了大量的内存,而且往往包含这大量的冗余。假设String与其他类的特性相同,势必造成如下局面:



         从中不难看到,内存中充斥这大量的冗余常量"pig","dog",而实际上我们只需要两个常量就可以了。为了解决这个问题,从而使java更高效的使用内存,JVM留出一块特殊的内存区域——“String常量池”。(对String够优待吧)

        所以当编译器遇到String s1 = "pig";时,首先检查String常量池中是否有存在"pig", 如果没有,则将pig放入常量池中,如下图:



      继续,当编译器遇到String s2 = "pig";时,首先检查String常量池中是否有存在"pig", 如果发现相同的常量"pig", 则只是把指向常量池中现有的,而不创建任何新的String对象。如下:



     到此,我们应该可以弄明白为什么1处运行的结果是true了吧!

     同时,我们也可以弄明白我上一篇文章的疑惑了,如果常量池中的发生了变化,则s1,s2将会同时变化,这也太可怕了吧,所以java绝对不允许出现这种情况!这也是我们常说的那句话:String对象不可改变!
         PS:由于担心String常量池出现问题,String类被标识为final。

        下面这个例子可能更加让你无法质疑,我就不在这里废话了:


public class Test {

  public static void main(String[] args) {

    String s1 = "pig";

    Person person = new Person();
    person.name = "pig";

    System.out.println(person.name == s1);// 输出为true

  }

}


Person.java



public class Person    {
  public String name;

}



    至于2处为false,这表明在String s3 = new String("pig")这种情况下,因为我们使用了new 关键字,所以将在常规内存(非String常量池)中创建了一个新的String对象,并且将引用它(到此和普通的对象一样)。此外,常量"pig"将放置在池内。

    众多面试答案中所说的String s3 = new String("pig");创建了两个对象,一个引用(句柄)是否指如下状态:(这里只是猜测,希望哪位高人给个正确答案,或者验证方法,小弟在此先行谢过!)





s3==s4比较的是s3,s4引用对象的地址,自然不相同,所以2处运行为false。



参考资料:《SCJP学习指南》

本文出自 “sunfish 翻车鱼” 博客,请务必保留此出处http://sunfish.blog.51cto.com/417500/113108