String基本特性
- String:字符串,使用一对“”引起来表示。
- String声明为final的,不可被继承
- String实现了Serializable接口:表示字符串是支持序列化的,实现了Comparable接口:表示String可以比较大小
- String在jdk8及以前内部定义了final char[] value 用于储存字符串数据。JDK9时改为byte[]。
- string pool是一个固定大小的HashTable,默认值大小长度是1009。如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能大幅下降。
- jdk6固定1009,jdk7默认60013,jdk8最小值1009。
String的内存分配
String类型的常量池
- 直接使用双引号声明出来的String对象会直接储存在常量池中。
- 如果不是双引号声明的String对象,可以使用String提供的intern()方法。
- 在JDK6及以前,字符串常量池存放在方法区中,JDK7及以后存放在堆中。
字符串拼接操作
- 常量与常量的拼接结果在常量池,原理是编译期优化
- 常量池中不会存在相同内容的常量
- 只要其中有一个是变量,结果就在堆中,相当于在堆空间中new String()。变量拼接的原理是StringBuilder
String s1 = "a";
String s2 = "b";
String s3 = s1 + s2 ;
System.out.println(s3==s4)
- 如果拼接结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并且返回次对象地址。
String.intern()
- 如果不是用双引号申明的String对象。可以使用String提供的intern方法:intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。
- 也就是说,如果在任意字符串上调用String.intern方法,那么其返回结果所指向的那个类的实例,必须和直接以常量形式出现的字符串实例完全相同。因此,下列表达式的值必定是true,
("a"+"b"+"c").intern() == "abc"
创建几个对象问题
String s= new String("ab");
- 一个对象是:new关键字在堆空间创建的
- 另一个对象时:字符串常量池中的对象
String s = new String("a")+new String("b");
- 对象1:new StringBuilder()
- 对象2:new String("a")
- 对象3:常量池中的"a"
- 对象4:new String("b")
- 对象5:常量池中的"b"
- 对象6:StringBuilder中的toString(),new String(value,0,count)=>new String(["a","b"],0,1);并不会把“ab”存在字符串常量池。
intern难题
String s = new String("1");
s.intern();
String s2 = "1";
Sout(s==s2);
String s = new String("1")+new String("2");
s.intern();
String s2 = "12";
sout(s==s2);