关于java:Stringintern-详解

6次阅读

共计 1549 个字符,预计需要花费 4 分钟才能阅读完成。

应用 String.intern() 能够保障雷同内容的字符串变量援用同一的内存对象

根本类型常量池

常量池就相似一个 JAVA 零碎级别提供的缓存,根本类型对应的缓冲池如下:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

常量池并不是创立时都会用到,比方 new Integer(123) 与 Integer.valueOf(123)

  • new Integer(123) 每次都会新建一个对象
  • Integer.valueOf(123) 会应用缓存池中的对象,屡次调用会获得同一个对象的援用

String 常量池

它的次要应用办法有两种:

  • 间接应用双引号申明进去的 String 对象会间接存储在常量池中。
  • 如果不是用双引号申明的 String 对象,能够应用 String 提供的 intern 办法。intern 办法会从字符串常量池中查问以后字符串是否存在,若不存在就会将以后字符串放入常量池中

接下来咱们次要来谈一下 String#intern 办法。

String#intern办法是一个 native 的办法,如果常量池中存在以后字符串, 就会间接返回以后字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回。

查看你 jdk 源码能够发现,它的大体实现构造就是: JAVA 应用 jni 调用 c ++ 实现的 StringTableintern办法, StringTableintern 办法跟 Java 中的 HashMap 的实现是差不多的, 只是不能主动扩容。默认大小是 1009。

要留神的是,String 的 String Pool 是一个固定大小的 Hashtable,默认值大小长度是 1009,如果放进 String Pool 的 String 十分多,就会造成 Hash 抵触重大,从而导致链表会很长,而链表长了后间接会造成的影响就是当调用String.intern 时性能会大幅降落(因为要一个一个找)。

例子

String s = new String("abc")这个语句创立了 2 个对象,第一个对象是”abc”字符串存储在常量池中,第二个对象在 JAVA Heap 中的 String 对象

public static void main(String[] args) {String s = new String("1"); 
    s.intern(); 
    String s2 = "1"; 
    System.out.println(s == s2); 
    String s3 = new String("1") + new String("1"); 
    s3.intern(); 
    String s4 = "11"; 
    System.out.println(s3 == s4); 
}

打印后果是

  • jdk6 下false false
  • jdk7 下false true

    public static void main(String[] args) {String s = new String("1"); 
    String s2 = "1"; 
    s.intern(); 
    System.out.println(s == s2); 
    String s3 = new String("1") + new String("1");
    String s4 = "11"; 
    s3.intern(); 
    System.out.println(s3 == s4); 
    }

    打印后果为:

  • jdk6 下false false
  • jdk7 下false false

jdk7 版本对 intern 操作和常量池都做了肯定的批改。次要包含 2 点:

  • 将 String 常量池 从 Perm 区挪动到了 Java Heap 区
  • 应用String#intern 办法时,如果存在堆中的对象,会间接保留对象的援用,而不会从新创建对象。

参考原文:深刻解析 String#intern

正文完
 0