zoukankan      html  css  js  c++  java
  • String直接赋值与使用new String的区别

    在研究String直接赋值与new String的区别之前我们需要先了解java中的字符串常量池的概念

    字符串常量池

    String类是我们平常项目中使用频率非常高的一种对象类型,jvm为了提升性能和减少内存开销,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用,如果不存在,初始化,并将该字符串放入字符创常量池中。

    使用String直接赋值

    String str = “abc”;可能创建一个或者不创建对象,如果”abc”在字符串池中不存在,会在java字符串池中创建一个String对象(”abc”),然后str指向这个内存地址,无论以后用这种方式创建多少个值为”abc”的字符串对象,始终只有一个内存地址被分配。==判断的是对象的内存地址,而equals判断的是对象内容。通过以下代码测试:
     
    String str = "abc";
    String str1 = "abc";
    String str2 = "abc";
    System.out.println(str==str1);//true
    System.out.println(str==str2);//true
    也就是str、str1、str2都是指向同一个内存地址。

    使用new String 创建字符串

    String str = new String(“abc”);至少会创建一个对象,也有可能创建两个。因为用到new关键字,肯定会在堆中创建一个String对象,如果字符池中已经存在”abc”,则不会在字符串池中创建一个String对象,如果不存在,则会在字符串常量池中也创建一个对象。
     
    String str = new String("abc");
    String str1 = new String("abc");
    String str2 = new String("abc");
    System.out.println(str==str1);//false
    System.out.println(str==str2);//false

    可以看出来,str、str1、str2指向的是不同的内存地址

            这里解释一下,对于通过 new 产生一个字符串(假设为 ”china” )时,会先去常量池中查找是否已经有了 ”china” 对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”china” 对象的拷贝对象。

    使用String拼接字符串

    项目中除了直接使用=赋值,也会用到字符串拼接,字符串拼接又分为变量拼接和已知字符串拼接
     
    String str = "abc";//在常量池中创建abc
    String str1 = "abcd";//在常量池中创建abcd
    String str2 = str+"d";//拼接字符串,此时会在堆中新建一个abcd的对象,因为str2编译之前是未知的
    String str3 = "abc"+"d";//拼接之后str3还是abcd,所以还是会指向字符串常量池的内存地址
    System.out.println(str1==str2);//false
    System.out.println(str1==str3);//true

    str和str1都是字符串常量所以在编译期就被确定了!而str2中有个str是引用不是字符串常量所以不会在编译期确定。

    而String是final的!所以在b+"c"的时候实际上是新创建了一个对象,然后在把新创建对象的引用传给c.

    所以在项目中还是不要使用new String去创建字符串,最好使用String直接赋值。

    String 有一个intern() 方法,native,用来检测在String pool是否已经有这个String存在。

     
    public String intern()
      返回字符串对象的规范化表示形式。
      一个初始时为空的字符串池,它由类 String 私有地维护。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。所有字面值字符串和字符串赋值常量表达式都是内部的。
    返回:一个字符串,内容与此字符串相同,但它保证来自字符串池中。
    考虑下面的问题:
    public static void main(String[] args) throws Exception {  
            String a =  "b" ;   
            String b =  "b" ;         
    
            System.out.println( a == b);               //true
            String d = new String( "d" ).intern() ; 
            String c = "d" ;  
            System.out.println( c == d);              //true
    
            System.out.println("------------------"); 
    
            String d1 = new String( "d" ) ; 
            String e1=d1.intern();
            String c1 = "d" ;  
            System.out.println( c1 == d1);          //false
            System.out.println( c1 == e1);          //true
            System.out.println( e1 == d1);         //false
    
            System.out.println("------------------"); 
    
            String s1=new String("kvill"); 
            String s2=s1.intern(); 
            System.out.println( s1==s2 );         //false
            System.out.println( s1+" "+s2 );     //kvill  kvill
            System.out.println( s2==s1.intern() ); //true
    
    }                  

    面试题:

    String s = new String(“xyz”); 产生几个对象?

             一个或两个。如果常量池中原来没有 ”xyz”, 就是两个。如果原来的常量池中存在“xyz”时,就是一个。对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。

    java中String new和直接赋值的区别

        对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
     
     
  • 相关阅读:
    noi 2011 noi嘉年华 动态规划
    最小乘积生成树
    noi 2009 二叉查找树 动态规划
    noi 2010 超级钢琴 划分树
    noi 2011 阿狸的打字机 AC自动机
    noi 2009 变换序列 贪心
    poj 3659 Cell Phone Network 动态规划
    noi 2010 航空管制 贪心
    IDEA14下配置SVN
    在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
  • 原文地址:https://www.cnblogs.com/wwct/p/12795827.html
Copyright © 2011-2022 走看看