Java intern()  方法

Java String类Java  String类


String的Intern方法
intern()方法返回调用者常量池中的引用,intern 正确使用后可节省巨大空间,调用"ab".intern()返回"ab",intern先检查字符串池中是否有"ab"这个字符串,存在则返回该字符串的引用,否则就将这个字符串添加到字符串池中,然后返回这个字符串的引用


有双引号括起字符串的地方就会用到ldc指令,执行ldc指令的字符串才会进入字符串常量池,比如String a = "hello"
intern的作用是把new出来的字符串的引用添加到stringtable中,java先计算string的hashcode,查找stringtable中是否已经有string对应的引用了
如果有返回引用(地址),如果没有把字符串的地址放到stringtable中,并返回字符串的引用(地址)
public class TestStr {
public static void main(String[] args) {
    String str1 = "a";
    String str2 = "b";
    String str3 = "ab";
    String str4 = str1 + str2;
    String str5 = new String("ab");//调用str5.intern时,才检查字符串池,执行ldc指令
    String str6 = "a" + "b";
    System.out.println(str3 == str6);  //true  静态字符串相加的结果会加入到字符串常量池中。
    System.out.println(str3 == str4);  //false  字符串相加,且含有变量,不会加入到常量池中。
    System.out.println(str5.equals(str3));  //true
    System.out.println(str5 == str3);   //false
    System.out.println(str5.intern() == str3); //true
    System.out.println(str5.intern() == str4);  //false
}
}


采用new创建出来的字符串不会进入字符串常量池;
字符串相加时,都是静态字符串的结果会添加到字符串池,
如果其中含有变量则不会加入到字符串池中。
当str5调用intern的时候,会检查字符串常量池中是否含有该字段,
由于之前定义的str3已经进入到该常量池汇总,所以str5和str3会得到相同的引用


String的stringtable表
java所有的类共享一个字符串常量池,比如A类中需要一个hello字符串常量,B类也需要同样的字符串常量,
都是从字符串常量池中获取的字符串,且获得得到的字符串常量的地址是一样的,
为了提高匹配速度,即更快的查找某个字符串是否存在于常量池,Java设计字符串常量池的时候,使用了一张stringtable表,
stringtable表保存了字符串的引用,类似于HashMap,根据字符串的hashcode找到对应entry,
如果有冲突,它可能是一个entry链表,然后Java再遍历entry链表,匹配引用对应的字符串,
如果找得到字符串,返回引用,如果找不到字符串,会把字符串放到常量池中,把引用保存到stringtable
//HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        String a = new String("test");
        System.out.println(a.intern() == a);//false
   }
}
双引号括起来的字符串,用到ldc指令,"test"会被添加到字符串常量池,
它的引用是string的char数组的地址,会被添加到stringtable中,
a.intern返回的是 string 中的char数组的地址,
和a的string实例化地址不一样
== 的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
String e = new String("jo") + new String("hn");
System.out.println(e.intern() == e);//true
new String("jo") + new String("hn") 会转为stringbuffer的append 然后tosring()出来,
实际上是new 一个新的string出来,在这个过程中,并没有双引号括起 john,不会执行ldc,不会把john的引用添加到stringtable中
所以intern的时候实际就是把新的string地址(即e的地址)添加到stringtable中并且返回回来


new String()创建了几个对象
Java中new String("hello")创建了几个String对象
String创建方式,是调用String的有参构造函数,
而这个有参构造函数的源码public String(String original)可以把代码转换为下面这种
String temp = "hello";  // 在常量池中
String str = new String(temp); // 在堆上
创建了2个String对象
temp指向在常量池中的对象
str指向堆上的对象
str内部的char value[]则指向常量池中的char value[]
所以这里的答案是2个对象。(参考深入浅出Java String)
假如就只有String str = new String("hello")
且此时的常量池的没有"hello"这个String,那么答案是两个;
如果此时常量池中,已经存在了"hello",那么此时就只创建堆上str,
而不会创建常量池中temp,(这里都是引用)所以此时答案就是1个


intern() 方法返回字符串对象的规范化表示形式。

遵循规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

语法

public String intern()

参数

返回值

一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。

实例

public class Test {
    public static void main(String args[]) {
        String Str1 = new String("www.facesoho.com");
        String Str2 = new String("WWW.facesoho.COM");

        System.out.print("规范表示:" );
        System.out.println(Str1.intern());

        System.out.print("规范表示:" );
        System.out.println(Str2.intern());
    }
}

以上程序执行结果为:

规范表示:www.facesoho.com
规范表示:WWW.facesoho.COM

Java String类Java  String类