String的特性
- 不变性
- 常量池优化
- final关键字修饰
String的不可变
String是不可变的,对于已经存在的String对象的修改都是重新创建一个新的对象然后把值保存进去。
String为什么要设计成不可变的?
- 便于实现字符串池。
- 使多线程安全。
- 避免安全问题。
- 加快字符串处理速度。
String的常量池优化
JVM为了减少内存开销和提升性能,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串池。 当需要使用字符串时,先去字符串池中查看该字符是否存在,如果存在则直接使用;若不存在,则初始化,并将该字符串放入字符串池中。
堆、栈、方法区和字符串池的位置
- 堆:堆区被所有线程共享,存储的是被new出来的对象。
- 栈:栈区中的数据都是私有的,存储的是基本数据类型的对象和自定义对象的引用。
- 方法区:方法区被所有线程共享,包含所有的在整个程序中永远唯一的元素,如class、static变量。
字符串池位于方法区中,被所有线程共享。
面试题: 两种创建字符串对象的方式
在Java中有两种创建字符串对象的方式:
@Test
public void testString() {
String s1 = "123";
String s2 = "123";
System.out.println(s1 == s2);
}
采用直接赋值的方式创建字符串时,JVM首先会在字符串池中查找是否存在“123”这个对象,如果不存在则在池中创建一个“123”对象,然后将“123”的引用地址返回给字符串常量s1,这样s1会指向池中“123”这个对象。s2在创建时候,字符串池已经存在了“123”这个对象,所以会直接把对象“123”的引用地址返回给s2,故以上代码的最终结果为true。
@Test
public void testString() {
String s1 = new String("123");
String s2 = "123";
System.out.println(s1 == s2);
}
采用new创建一个字符串对象s1时,JVM首先会在字符串池中查找是否存在“123”这个对象,如果不存在则在池中创建一个“123”对象,如果存在则直接在堆中创建一个“123”字符串对象,然后将堆中的这个“123”对象的地址返回赋给s1。但是由于在使用new对象创建字符串对象时,每次new出来的都是一个新的对象,因此此代码执行结果为false。
面试题:String创建对象的数量
下列有几种情况,均不考虑字符串池已有的情况,下列代码创建了多少个对象?
一:
String str = "ABC";
仅在池中创建了一个"ABC"对象。
二:
String str = new String("ABC");
创建了两个对象:
- 第一个对象:在池中创建"ABC"。
- 第二个对象:通过new关键字在堆中创建的new String()对象。
三:
String str = new String("A" + "B");
创建了四个对象
- 第一个对象:在池中创建"A"。
- 第二个对象:在池中创建"B"。
- 第三个对象:在池中创建"AB"。
- 第四个对象:通过new关键字在堆中创建的new String()对象。
|