zoukankan      html  css  js  c++  java
  • 关于String s = new String("xyz");创建了几个字符串对象?的问题

    引用自这位朋友:http://blog.sina.com.cn/s/blog_6a6b14100100zn6r.html

    首先让我们了解几个概念:

    栈:由JVM分配区域,用于保存线程执行的动作和数据引用。

    堆:由JVM分配的,用于存储对象等数据的区域。

    常量池constant pool :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.这是一个特殊的共享区域,可以在内存中共享的不经常改变的东西,都可以放在这里。

    进入正题:

    String a = "abc";①
    String b = "abc";②

    使用String a = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。
    ①代码执行后在Constant Pool中创建了一个值为abc的String对象,②执行时,因为Constant Pool中存在"abc"所以就不在创建新的String对象了。

    String   c   =   new   String("xyz");①
    String   d   =   new   String("xyz");②

    让我们来看看这两句代码在内存中发生了什么,①Class被CLassLoader加载时,你的"xyz"被作为常量读入,在constant   pool里创建了一个共享的"xyz",然后当调用到new   String("xyz")的时候,会在heap里创建这个new   String("xyz");②由于constant   pool中存在"xyz"所以不再创建"xyz",然后创建新的new   String("xyz")。
    对于String c = new String("xyz");的代码,与String a = "abc"不同的是一概在堆中创建新对象,不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。 
    程序1
    String   s1   =   new   String("xyz");     //创建二个对象,一个引用 
    String   s2   =   new   String("xyz");     //创建一个对象,并且以后每执行一次创建一个对象,一个引用 
    程序2 
    String   s3   =   "xyz";     //创建一个对象,一个引用   
    String   s4   =   "xyz";     //不创建对象,只是创建一个新的引用

    重要的是理解constant pool与new关键字

    当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。(无论怎样都返回池中的对象)

    下面的这个例子能帮助我们更深入的理解String的存储和赋值原理

    String str1 = new String("123");
    String str2 = "123";

    String str3 = str1.intern();
            
           System.out.println((str1 == str2) +","+ (str3 == str2));

           输出 false,true
                    
           String str4 = new String("234");
           String str5 = new String("234");
            
           String str6 = str4.intern();
           String str7 = str5.intern();
            
           System.out.println((str4 == str5) +","+ (str6 == str7));

           输出 false,true

    你知道在java中除了8中基本类型外,其他的都是类对象以及其引用。所以 "xyz "在java中它是一个String对象.对于string类对象来说他的对象值是不能修改的,也就是具有不变性。 


    看: 
    String   s= "Hello "; 
    s= "Java "; 
    String   s1= "Hello "; 
    String   s2=new   String( "Hello "); 

    啊,s所引用的string对象不是被修改了吗?之前所说的不变性,去那里了啊? 

    你别着急,让我告诉你说发生了什么事情: 
    在jvm的工作过程中,会创建一片的内存空间专门存入string对象。我们把这片内存空间叫做string池。 

    String   s= "Hello ";当jvm看到 "Hello ",在string池创建string对象存储它,并将他的引用返回给s。 
    s= "Java ",当jvm看到 "Java ",在string池创建新的string对象存储它,再把新建的string对象的引用返回给s。而原先的 "Hello "仍然在string池内。没有消失,他是不能被修改的。 

    所以我们仅仅是改变了s的引用,而没有改变他所引用的对象,因为string对象的值是不能被修改的。 

    String   s1= "Hello ";jvm首先在string池内里面看找不找到字符串 "Hello ",找到,返回他的引用给s1,否则,创建新的string对象,放到string池里。这里由于s= "Hello "了,对象已经被引用,所以依据规则s和s1都是引用同一个对象。所以   s==s1将返回true。(==,对于非基本类型,是比较两引用是否引用内存中的同一个对象) 

    String   s2=String( "Hello ");jvm首先在string池内里面看找不找到字符串 "Hello ",找到,不做任何事情,否则,创建新的string对象,放到string池里面。由于遇到了new,还会在内存上(不是string池里面)创建string对象存储 "Hello ",并将内存上的(不是string池内的)string对象返回给s2。所以s==s2将返回false,不是引用同一个对象。 

    好现在我们看题目: 
    String   s   =   new   String( "xyz "); 
    首先在string池内找,找到?不创建string对象,否则创建,   这样就一个string对象 
    遇到new运算符号了,在内存上创建string对象,并将其返回给s,又一个对象 

    所以总共是2个对象 

     

    一个例子: 
    public class Test 

    public static void main(String [] args) 

    String s1=new String("test");//创建2个对象,一个Class和一个堆里面 
    String s2="test";//创建1个对象,s2指向pool里面的"test"对象 
    String s3="test";//创建0个对象,指向s2指想pool里面的那个对象 
    String s4=s2;//创建0个对象,指向s2,s3指想pool里面的那个对象 
    String s5=new String("test");//创建1个对象在堆里面,注意,与s1没关系 

    System.out.println(s2=="test");//true s2=="test"很明显true 
    System.out.println(s2==s3);//true,因为指向的都是pool里面的那个"test" 
    System.out.println(s2==s4);//true,同上,那么s3和s4...:) 
    System.out.println(s1==s5);//false,很明显,false 
    System.out.println(s1==s2);//false,指向的对象不一样,下面再说 
    System.out.println(s1=="test");//false,难道s1!="tset"?下面再说 

    System.out.println("---------------"); 

    s1=s2; 
    System.out.println(s1=="test");//true,下面说 


    说明:1,System.out.println(s1==s2);很明显,s2指向的对象"test"是在pool里面,而s1指向的是堆里面的"test"对象(s1指向的内存区),所以返回false. 
    2,System.out.println(s1=="test");s1指向的是堆里面的"test"对象(s1指向的内存区),而"test"是程序 刚刚建立的(其实是共用pool里面的那个已经创建了的"test"对象,也就是我们s2="test"时候,在pool里面创建的),所以s1指向的堆 里的"test"对象 
    和"test"(pool里面)并不是一样个对象,所以返回false. 
    3,当我们s1=s2;的时候,很明显,把s2的指给了s1,s1指向pool里面的"test",这个时候,s2也指向了pool里面的"test"对 象了,当System.out.println(s1=="test");时候,java虚拟机创建"test"对象,注意,其实没创建,和前面讲的一 样,公用s1="test"创建的"test"对象(pool里面的),所以,s1=="test"(pool里面的),同 样,s1=s2=s3=s4! 

    而为什么在网上都说String s=new String("test");创建了2个对象?那可能因为它就写这么一句代码,误让人默认的认为执行代码之前并不实例任何一个String对象过

    (也许 很多人不会这么想,),跟着别人或者不经思考的就说2个,斟是说存放在栈内存中专门存放String对象引用的s变量是一个对象!实在不可原谅!

    所以当有面试官问起,String   s2=new   String( "Hello "); 创建几个对象时,正确答案应该回答,视情况而定,当常量池中没有“Hello”对象时是创建两个,一个存放在常量池中,另一个存放在堆(内存)中。

  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/xuxinstyle/p/9345647.html
Copyright © 2011-2022 走看看