jvm学习第九天—StringTable(字符串常量池)

标题:jvm学习第九天—StringTable(字符串常量池)

学习内容:

1、String的基本特征与内存分配
2、 字符串的拼接操作
3、 关于intern()的理解及题目


内容详情:

1、String的基本特征与内存分配

String的基本特性

String :字符串,使用一对""引起来表示。
String s1 = “atguigu”;//字面量的定义方式
String s2 = new String ( “hello”) ;
String声明为final的,不可被继承
String实现了serializable接口:表示字符串是支持序列化的。
实现了comparable接口:表示String可以比较大小
String在jdk8及以前内部定义了final char[] value用于存储字符串数据。jdk9时改为byte[]

字符串常量池中是不会存储相同内容的字符串的
String的String Pool是一个固定大小的Hashtable,默认值大小长度1009。如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降。
使用-XX : StringTablesize可设置StringTable的长度
在jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTablesize设置没有要求在jdk7中,StringTable的长度默认值是60013,1009是可设置的最小值。

String的内存分配

在Java语言中有8种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。 常量池就类似一个Java系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的.
String类型的常量池比较特殊。
它的主要使用方法有两种。
> 直接使用双引号声明出来的String对象会直接存储在常量池中。 比如:String info= “atguigu .com” ;
如果不是用双引号声明的String对象,可以使用String提供的intern ()方法。这个后面重点谈

Java6及以前,字符串常量池存放在永久代。
Java 7 中 oracle的工程师对字符串池的逻辑做了很大的改变,即将字符串常量池的位置调整到Java堆内。

所有的字符串都保存在堆(Heap)中,和其他普通对象一样,这样可以让你在进行调优应用时仅需要调整堆大小就可以了。
字符串常量池概念原本使用得比较多,但是这个改动使得我们有足够的理由让我们重新考虑在Java 7 中使用string.intern ( )。

2、 字符串的拼接操作

常量与常量的拼接结果在常量池,原理是编译期优化
只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder
如果拼接的结果调用intern ()方法,如果常量池中有这个对象,则方法返回的结果为这个对象的地址,如果常量池中没有这个对象,则先在常量池里创建,再返回这个对象的地址。

下面举几个例子描述一下
String s1=“aaa”;
String s2 = “bbb”;
String s3 = “aaabbb" ;
String s4 = "aaa” + “bbb” ;
String s5 = s1 + “bbb” ;
String s6 = "aaa” + s2;
String s7= s1 + s2
s3=s4 编译器优化,s4实际上就是aaabbb
s4!=s5 有变量的话,s5对象放在堆中(相当于在堆中new String()),而s4在字符串常量池里
s5!=s6 s5和s6是堆中的不同对象

如下的s1 + s2的执行细节:(变量s是我临时定义的)
StringBuilder s = new stringBuilder();
s.append(“a”)
s.append("“b”)
s.toString(约等于new string( “ab”))

3、 关于intern()的理解及题目

intern()方法的理解:

调用intern ()方法,如果常量池中有这个对象,则方法返回的结构为这个对象的地址,如果常量池中没有这个对象,则先在常量池里创建,再返回这个对象的地址。

题目: new string ( " ab")会创建几个对象?
两个:

一个是堆中的new string()对象,另一个是在字符串常量池里面创建一个对象"ab".

拓展: new String ( “a”) +new string ( “b”)呢?
六个:

1.进行拼接操作的StringBuilder s = new stringBuilder();
2.new String(“a”)
3.字符串常量池的a
4.new String(“b”)
5.字符串常量池的b
6.toString方法里面的new String(“ab”)
要说明的是,常量池里面并没有ab.

intern()方法的面试难题
String s = new String(original: “1”);
s.intern();
String s2 = “1”;
System.out.println(s == s2);//jdk6: false jdk7/8: false

String s3 = new String( original: “1"”) + new String( original: “1”);
s3.intern();
String s4 = “11”;
system.out.println(s3 ==s4);//jdk6: false jdk7/8: ture

首先看jdk6

上面的s指向的地址是堆中"1"的地址,而s2指向的地址是字符串常量池"1"的地址
下面的s3相当于new String(“11”),但是字符串常量池里面没有"11",s3.intern()就在常量池里面放了一个"11",s3还是指向的地址是堆中"11"的地址,s4指向的地址是字符串常量池"11"的地址,所以不相等

jdk7字符串常量池放在了堆中

上面的s指向的地址是堆中"1"的地址,而s2指向的地址是字符串常量池"1"的地址
下面的s3相当于new String(“11”),但是字符串常量池里面没有"11",由于字符串常量池在堆中,为了节省内存,s3.intern()实际上就是在常量池里面放了一个指向堆中"11"的地址,而没有再去创建一个"11"。由于s4指向的地址是常量池中的地址,常量池中又指向堆中"11"的地址,最后两者所指向的地址一样,相等

这几个例子就把原理讲得很清楚了,只要搞懂这些指向的地址,就懂了

拼接操作append方法和intern()方法都提高了效率


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值