String 简述及intern方法
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html
在JAVA中有8种基本类型和一种特殊字符类型:String。这些类型为了运行更快,更节省内存,使用了常量池的概念。
String声明为final,表示不可继承,所有的属性也是final类型。字符串常量:string一经创建值便不可修改。由于它的不可变性,因此string相关的拼接,截取等操作都会产生新的对象。String底层使用char数组方式进行存储。
常见生成string方式:
1、String s = new String("abc"); 创建了二个对象:1、第一个对象 "abc"对应常量池中;第二个对象 在JAVA heap中的String对象。
2、String a = "11"; 声明使用双引号直接存储到常量池中。
3、String.valueOf(1); 底层使用new String(char[])的方式实现转换
String#intern方法
native String intern():目的是提示 JVM 把相应字符串缓存起来,以备重复使用。。
intern() 是一种显式排重的机制。需要使用者显式调用它,这样一是不方便,二是每次显式比较麻烦。
要注意的是,String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找)。
在 jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。
在jdk7中,StringTable的长度可以通过一个参数指定: -XX:StringTableSize=99991
1 public static void main(String[] args) { 2 String s1 = new String("1"); 3 String s2 = "1"; 4 s1.intern(); 5 System.out.println(s1 == s2); 6 7 String s3 = new String("1") + new String("2"); 8 String s4 = "12"; 9 s3.intern(); 10 System.out.println(s3 == s4); 11 }
输出结果: false false
代码行7:生成两个对象,分别对应常量池"1","2", JAVA heap中的s3引用指向的对象。 s3引用指向对象的内容是"12",但是此时常量池中没"12"对象。"Java语言为字符串连接运算符(+)以及将其他对象转换为字符串提供了特殊的支持。字符串连接是通过StringBuilder(或StringBuffer)类及其append方法实现的。字符串转换是通过toString方法实现的"
代码行8:s4是显式声明,直接向常量池查找不到,则创建对象。
代码行9:intern()返回字符串对象的规范表示形式。在调用intern方法时,如果池中已经包含了由equals(object)方法确定的与该字符串对象相等的字符串,则返回池中的字符串。否则,该字符串对象将被添加到池中,并返回对该字符串对象的引用。
如果s4 变换下位置
1 public static void main(String[] args) { 2 String s = new String("1"); 3 String s2 = "1"; 4 s.intern(); 5 System.out.println(s == s2); 6 7 String s3 = new String("1") + new String("2"); 8 s3.intern(); 9 String s4 = "12"; 10 System.out.println(s3 == s4); 11 }
输出结果: false true (以上基于jdk8运行)
代码行8:先调用intern(),会在常量池创建对象并返回对象引用。
代码行9:s4声明式显示,在常量池中找到并返回对象。
因此,s3==s4是指向同一个对象。