StringTable
String的基本特性
-
string:字符串使用一对""引起来表示。string声明为final的,不可被继承
-
string实现了serializable接口:表示字符串是支持序列化的。
-
实现了Comparable接口:表示string可以比较大小
-
string在jdk8及以前内部定义了final char[ ] value用于存储字符串数据。jdk9时改为byte[ ]
- 结论: String再也不用char[]来存储啦,改成了byte[]加上编码标记,节约了一些空间。
-
string:代表不可变的字符序列。简称:不可变性。
-
当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
-
当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
-
当调用string的replace ()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
-
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
-
字符串常量池中是不会存储相同内容的字符串的。
-
使用**-XX : StringTablesize**可设置StringTable的长度
-
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 ( )。
-
. Java8元空间,字符串常量在堆
字符串拼接操作
-
1.常量与常量的拼接结果在常量池,原理是编译期优化
-
2常量池中不会存在相同内容的常量。
-
3.只要其中有一个是变量,结果就在堆中。变量拼接的原理是stringBuilder
- 如果拼接符号的前后出现了变量,则相当于在堆空间中new String()
-
4.如果拼接的结果调用intern ()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。
- 字符串拼接操作不一定使用的是StringBuilder!
- 如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
- 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。
intern()的使用
- jdk1.6中,将这个字符串对象尝试放入串池。
- 如果串池中有,则并不会放入。返回已有的串池中的对象的地址
- 如果没有,会把此对象复制一份,放入串池,并返回串池中的对象地址
- Jdk1.7起,将这个字符串对象尝试放入串池。
- 如果串池中有,则并不会放入。返回已有的串池中的对象的地址
- 如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址
G1中的String去重操作
-
**堆上存在重复的string对象必然是一种内存的浪费。**这个项目将在G1垃圾收集器中实现自动持续对重复的string对象进行去重,这样就能避免浪费内存。
-
实现
- 当垃圾收集器工作的时候,会访问堆上存活的对象。对每一个访问的对象都会检查是否是候选的要去重的string对象。
- 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的string对象。
- 使用一个hashtable来记录所有的被string对象使用的不重复的char数组。当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组。
- 如果存在,string对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。
- 如果查找失败,char数组会被插入到hashtable,这样以后的时候就可以共享这个数组了。
-
命令行选项
- UsestringDeduplication (bool):开启string去重,默认是不开启的,需要手动开启。
- PrintstringDeduplicationstatistics (bool):打印详细的去重统计信息
- stringDeduplicationAgeThreshold (uintx):达到这个年龄的string对象被认为是去重的候选对象
面试题
题目: new String ( “ab”)会创建几个对象?
-
一个对象是:new关键字在堆空间创建的
-
另一个对象是:字符串常量池中的对象"ab"。 字节码指令:ldc
拓展: new String ( “a”) + new String ( “b”)呢?
-
对象1:new StringBuilder()
-
对象2: new String(“a”)
-
对象3: 常量池中的"a"
-
对象4: new String(“b”)
-
对象5: 常量池中的"b"
-
深入剖析: StringBuilder的toString():
- 对象6 :new String(“ab”)
- 强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
")
-
对象5: 常量池中的"b"
-
深入剖析: StringBuilder的toString():
- 对象6 :new String(“ab”)
- 强调一下,toString()的调用,在字符串常量池中,没有生成"ab"