本文为个人学习笔记,可能会有错误之处,仅供参考,视频链接如下:
尚硅谷宋红康JVM全套教程(详解java虚拟机)_哔哩哔哩_bilibili0基础如何学起?宋红康30天搞定Java核心:BV1Kb411W75N一键三连+收藏,关注硅谷更辉煌!制作不易,感谢支持!全套课程分为《内存与垃圾回收篇》《字节码与类的加载篇》《性能监控与调优篇》三个篇章,由尚硅谷宋红康老师亲自主刀,亲手绘制的图示,仅上篇就有50张之多...内容之强悍,可见一斑!
https://www.bilibili.com/video/BV1PJ411n7xZ?p=128&spm_id_from=pageDriver
1. String的基本特性:
String就是字符串类型,定义方式有两种:
String s1 = "hello";
String s2 = new String("hello");
String类是final修饰的,不可以被继承。
JDK1.9之后String、StringBuffer、StringBuilder从char[]改成byte[]了。
String代表不可变的字符序列,简称不可变性。
字面量定义的方式,存储在字符串常量池中。字符串常量池是不会存储相同内容的字符串的。Stringpool是一个固定大小的HashTable,默认值大小长度是1009.如果放进StringPool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了之后直接会造成的影响就是当调用String.intern时性能会大幅下降。
使用-XX:StringTableSize可设置StringTable的长度。
2. String的内存分配:
在java语言中,有8中基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
StringTable为什么要从永久代调整到堆空间中?
1. permSize默认比较小;
2. 永久代垃圾回收频率低;
3. String的基本操作:
常量池中是不存放重复字符串的。
Java语言规范里要求完全相同的字符串字面量,应该包含同样的Unicode字符串序列(包含同一份码点序列的常量),并且必须是指向同一个String类实例。
4. 字符串拼接操作:
1.常量与常量的拼接结果在常量池,原理是编译器优化。
2.如果拼接符号的前后只要其中有一个是变量,就相当于在堆空间中new String(),结果就在堆中。变量拼接的原理是StringBuilder
3.只要拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。
字符串拼接操作不一定使用的是StringBuffer
关于StringBuffer的改进思路:
在实际开发中,如果基本确定要前前后后添加的字符串长度不高于某个限定值max时,建议使用
StringBuilder s = new StringBuilder(max);//new char[max]
如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译器优化,即非StringBuilder的方式。
针对与于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议用上。
5. intern()的使用:
intern():判断字符串常量池中是否存在当前值。如果存在,则返回常量池中的当前字符串的地址;如果字符串常量池不存在当前字符串,则在常量池中新建当前字符串,然后返回该对象的地址。
保证变量指向的是字符串常量池中的数据有2种方式:
1. String s = "a";
2. String s = new String("a").intern();
String s = new StringBuilder("a").toString().intern();
new String("ab")会创建几个对象?
2个:堆中有一个,常量池中有一个。
new String("a") + new String("b")会创建几个对象?
1.new StringBuilder()
2.new String("a")
3.常量池中的"a"
4.new String("b")
5.常量池中的"b"
6.在进行"+"操作之后,StringBuffer中的append()方法之后,深入剖析:StringBuilde中的toStirng():
new String("ab")
但是toString调用之后,在字符串常量池中并没有生成"ab"
s.intern()在字符串常量池中创建了一个新的对象,就会有一个新的地址。
6.StringTable的垃圾回收:
7. G1中的String去重操作: