其他分享
首页 > 其他分享> > JVM-String Table

JVM-String Table

作者:互联网

1 String的基本特性

1)字符串,使用一对”“引起来表示。

2)String 声明为final,不可被继承

3)String实现了Serializable接口:表示字符串是支持序列化的。实现了comparable接口,表示String是可以比较大小的。

4)String在JDK8及其以前使用Final char[] value用于存储字符串数据。JDK9改为byte[],因为大部分字符串是拉丁符,一个字节就能存下,这些字符一个byte就能存储。但是中文需要两个byte,因此还增加了字符编码集的标识。

5)String:代表不可变的字符序列

6)通过字面量赋值和new赋值的区别。

例如String str1="ABC"; 和String str2 = new

String("ABC"); 前者可能创建一个对象也可能不创建对象,后者创建两个或者一个。前者如果”ABC"在常量池中则不创建,后者在堆区创建一个对象,如果常量池中不存在则再创建一个。

7)字符串常量池中不会存储相同内容的字符串。

String的String pool是一个固定大小的Hashtable如果放进String pool的string非常多,就会造成hash冲突严重,从而导致链表长度很长,大幅度降低查询效率。

jdk6的默认值大小长度为1009,jdk7默认大小为60013。可以使用-XX:StringTableSize来设置其长度,jdk8中对设置长度有最低要求,为1009。

2 String内存分配

java中有八种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中更快、更节省内存,都提供了一种常量池的概念。

java常量池就类似一个java系统级别提供的缓存。8种数据类型的常量池都是系统协调的,S特ing类型比较特殊,主要两种:1.直接双引号声明出来的String 对象对直接存储在常量池中。2.如果不是双引号声明的String对象,可以使用intern()方法。

3 字符串的拼接操作

1)常量与常量的拼接结果在常量池,原理是编译器优化。

2)常量池中不会存在相同的常量。

3)只要其中有一个变量(final修饰的虽然是引用,不算变量),结果就在堆中,变量的拼接原理StringBuilder。

1.new一个StringBuilder

2.append("a")

3.append("b")

4s.tostring(),约等于new String("ab")

补充:jdk5.0之前使用stringbuffer,之后使用stirngbuilder。

4)如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。

拼接操作和append的效率对比:

拼接操作的效率远小于append,因为每一次拼接操作都会创建一个strngbuilder和一个string对象。

4 intern()的使用

native修饰的本地方法

intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。在任意字符串上调用String.intern()方法,其返回的结果所指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。

如何确保变量s指向的是字符串常量池中的数据?

方式一:String s ="shkstart";//字面量赋值

方式二:调用intern方法

String s= new String("shkstart").intern();

String s = new StringBuilder("shkstart").toString().intern();

5 new String("ab")会创建几个对象?new String("a")+new String("b")呢?

两个,看字节码就知道是两个。一个是new关键字在堆空间创建,一个是在常量池,字节码中的ldc指令。

六个:

1.StringBuilder.

2.String("a")

3.常量池“a”

4.String("b")

5.常量池”b“

6.String("ab"):tostirng的调用,在常量池中没有生成“ab"

6 intern()的使用jdk6 vs jdk7/jdk8

jdk1.6中,将这个字符串对象尝试放入串池。如果池中有,并不会放入。返回已有串池的对象的地址。如果没有,会把对象复制一份放入串池中,并返回串池中的对象地址。

jdk7起,如果串池有,不会放入,返回串池中对象地址,没有则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址。

小结:jdk6的时候字符串常量池在永久代,1.7以后均位于堆区,而对象创建于堆区,所有本着节约空间的想法,常量池中直接引用对象地址。

String s = new String("1");
s.intern();//调用此方法时,常量池中已经存在了”1“
String s2 = "1";
System.out.println(s1==s2);//jdk6:false jdk7/jdk8:false

String s3 = new String("1")+new String("1");//常量池中没有”11“
s3.intern();//jdk7没有创建新的对象,直接使用堆中对象的地址。
String s4 = "11";
System.out.println(s3==s4);//jdk6:false jdk7/jdk8:true

如果s3.intern("11")和 String s4 = "11";结果为false,因为前者已经直接在常量池中创建了一个对象。

intern()测试执行效率:(空间使用上)

在拥有大量重复对象的时候执行效率提升很大

虽然依旧会创建对象,但是对象实例指向的是常量池中引用,没有指向的对象会被销毁。

 

 

标签:String,池中,intern,JVM,new,字符串,Table,常量
来源: https://www.cnblogs.com/slwyj/p/15072281.html