String对象解析

来源:互联网 发布:双十一淘宝津贴怎么用 编辑:程序博客网 时间:2024/06/06 02:49
  • 简介

    String对象(线程安全,可查看源码)又称为不可变字符串,即不能修改字符串中的字符。其优点:编译器可以让字符串共享。
    Java
设计者认为共享带来的高效率远胜于提取、拼接字符串所带来的低效率(字符串更多的是进行比较)。
    每个用双括号括起来的字符串(称为字符串常量),总是指向字符串池中的一个对象

  • 存储

    JVM为了减少字符串对象的重复创建,维护了一个特殊的内存"字符串常量池"(位于方法区)。
    由于字符串对象的大量使用(它是一个对象,一般而言对象总是在堆中分配内存),为了节省内存空间和运行时间,在编译阶段就把所有的字符串文字放到字符串常量池中,该池中所有相同的字符串常量被合并,只占用一个空间。

  • 创建
1)字面量直接定义
    如:String str=“seraph
    JVM在字符串常量池中寻找内容为seraph的对象:
    若找不到则创建这个对象,然后将创建的对象的引用放入字符串常量池,并且将引用返回给变量str。
    若找到,则将已存在的字符串对象的引用返回给str。

2)new关键字标准构造
    如:String str=new String(“seraph”)
    new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;
    如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则,将使得堆中的字符串永远是池中的子集,导致浪费池的空间)
    如果想将这个对象的引用放入字符串常量池,则使用intern方法,调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将其返回给变量,否则将引用加入并返回给变量。

3)串联生成
    常量表达式(constant expression),即使用+连接常量字符串。
    如String  s  =  “a” + "b" + "c"; 编译器将在编译时优化为String s = “abc”;

    如果右操作数含有一个或一个以上的字符串引用时,则在运行时堆中再建立一个字符串对象,返回引用。
    如String s=str+ “ous”; 

测试:
String a = "abc";String b = "abc";String c = "a" + "b" + "c";String d = new String("abc");String e = new String("abc".getBytes());String f = e.intern();String temp = "c";String g = "ab" + temp;System.out.println(a == b);//trueSystem.out.println(b == c);//trueSystem.out.println(d == a);//falseSystem.out.println(e == a);//falseSystem.out.println(f == a);//trueSystem.out.println(g == a);//false


字符串引用关系总结:
1)字符串字面量不管是否在相同包/相同类都引用相同对象。
2)通过常量表达式(constant expression)计算的字符串在编译时被计算并被视为字符串字面量
3)运行时通过串联计算的字符串是新创建的,因此引用不同。
4)显式的调用计算后的String对象的intern方法和之前相同内容的任意已经存在的字符串字面量是相同的对象。 

  • hashCode
    hashCode中存在良性数据竞争,即hashCode是延迟初始化的,但是因为初始化多少次都无所谓,所以数据竞争是良性的。

参考:
《JLS8》3.10.5 String Literals
http://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/
http://my.oschina.net/xiaohui249/blog/170013?p=3#comments
http://www.importnew.com/10756.html

转载请注明出处!
0 0