JVM学习笔记:StringBuilder

String的基本特性

  • String:字符串,用""引起来表示

  • String 声明为final,不可以被继承

  • String实现了Serializable接口,表示字符串时支持序列化的

  • String实现了Comparable接口,表示String可以比较大小

  • JDK8之前用char[]存储字符串数据,JDK9改为byte[]

  • String代表不可变得字符序列

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

  • String的 String Pool是一个固定大小的Hashtable,默认大小长度是1009.

  • 使用-xx:stringTableSize可设置StringTable的长度

  • JDK8中StringTable默认长度改为60013,1009是可设置的最小值

String的内存分配

常量池类似于一个Java系统级别提供的缓存,8种基本数据类型的常量池都是系统协调的。

对于特殊的String类型的常量池:

  1. 直接使用双引号声明出来的String对象会直接存储在常量池中

  2. 如果不是用""声明的String对象,可以使用String提供的intern()方法

Java6,字符串常量池放在永久代

Java7,将字符串常量池位置调整到了堆空间中

Java8,虽然去掉了永久代改为元空间,但是字符串常量还在在堆中

String的基本操作

字符串拼接操作

  1. 常量与常量的拼接结果在常量池,原理是编译期优化

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

  3. 只要其中有一个是变量结果就在堆里面

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

intern():判断字符串常量池中是否存在javaEEhadoop值,若存在则返回常量池中的地址,若字符串常量池中不存在,则在常量池中加载一份javaEEhadoop,并返回对象的地址

只要String拼接的连接符两边出现了变量就会new StringBuilder

String s1="a";
String s2="b";
String s3=s1+s2;
"s1+s2"的执行细节:
    StringBuilder s =new StringBuilder();
    s.append("a");
    s.append("b");
    s.toString();

StringBuilder的append()方法添加字符串的效率要远远高于直接String字符串拼接

因为append()方法自始至终只会创建一个StringBuilder对象

StringBuilder s =new StringBuilder();
for(int i=0;i<10;i++){
    s.append("a");
}

在实际开发中若能确定前后添加的字符串长度不高于某个限定值highlevel,建议使用构造器

StringBuilder s = new StringBuilder(highlevel)

intern()的使用

若在任意字符串上调用String.intern方法,那么其返回结果所指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。所以

("a"+"b"+"c").intern()=="abc" //true

Interned 就是确保字符串在内存里只有一份拷贝,节约内存空间

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

1. String s ="snhstart";
2. String s = new String ("snhstart").intern();
new String("ab")会创建几个对象 ?  //2个
    一个对象是new关键字,在堆空间创建的
    一个对象是字符串常量池中的对象,字节码指令:ldc
​
String str = new String("a")+new String("b")  //
    对象1:new StringBuilder()
    对象2:new String("a")
    对象3:常量池中的"a"
    对象4:new String("b")
    对象5:常量池中的"b"
    
toString()的调用在字符串常量池中,没有生成"ab"
String s=new String ("1")
String s1 = "1"
system.out.println(s==s1);//false
s是堆空间中new的地址,s1是字符串常量池中"1"的地址
 
String s2 = new String("1")+new String("1") 
//s2变量记录的地址为:new String("11")的地址,此行代码后字符串常量池中没有生成"11"
s2.intern();//在字符串常量池中生产"11"
/*在jdk6中创建了一个新的对象,有新的地址
在jdk7中常量池中并没有创建“11”,而是创建了一个指向堆空间“11”的地址
因为7以后,字符串常量池放入堆空间,那么intern判断已经new了一个“11”就不在在字符串常量池中创一个“11”,而是创一个指向new “11”地址指针,所s3虽然是常量池中的“11”但是实际就是new的s2的地址 
*/
String s3="11";
system.oout.println(s2==s3);//jdk6:false,jdk7:true 

G1的String去重操作

去底层new的char型数组的的重复的操作,并非常量池的

  • 当垃圾收集器工作的时候回访问堆上存活的对象。对每一个访问的对象都会检查是否候选的要去重的对象

  • 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列:从队列删除这个元素,然后尝试去重它引用的String对象

  • 使用hashtable来记录所有的被String对象使用的不重复的char数组,去重时差这个hashtable来看堆上是否已经存在一个一模一样的char数组

  • 如果存在String对象会被调整引用那个数组,释放原来数组的引用,最终被垃圾收集器回收掉

  • 如果查找失败,char数组会被插入到hashtable,这样以后就可以共享这个数组

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值