String 字符串全面理解
它的本质
“Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings.Because String objects are immutable they can be shared”
大致意思:字符串是一个常量,它们的值创建后无法更改,字符串缓冲区支持可变 字符串,因为字符串对象是不可变的,所以可以分享它们
1、String 的基本概念
1.1、字符串的定义
字符串可以分为两大类:一类是创建之后不会再做修改和变动的字符串变量;另一类是创建之后允许再做修改的字符串变量
思考:为什么字符串创建后不会修改和变动,创建后可以修改的字符串变量是什么类?(下面一一解读)
1.2、字符串变量的创建
- 格式一:
String s; //声明字符串型引用变量s,此时s的值为null
s = new String("字符串");//在堆内存分配空间,并将s指向该字符串首地址
- 格式二:
String s = new String("字符串");
- 格式三
String s = "字符串"//声明字符串变量时直接初始化
由于字符串是引用类型变量,所以其存储方式与数组方式基本相同(详情在第3节)
1.3、字符串的拼接(+)
Java语言定义 “+” 运算符可以用于两个字符串的连接操作,如:
str = "Hello" + "Java";
如果字符串与其他类型的变量进行 “+” 运算,系统自动将其他类型数据转换为字符串型 ,如:
int i = 10;
String s = "s" + i //结果为:"s10"
Tips:利用String类创建的字符串变量,一旦被初始化或赋值,它的值和所分配的内存内容就不可再改变,如果硬要改变它的值,就会产生一个新的字符串,如:
String str1 = "Java";
str1 = str1 + "Good";
上面的过程再程序的解释过程:程序首先产生str1 的一个字符串对象并再内存中申请了一块空间,由于发现有需要重新赋值,再原来的空间已经不可能再追加新的内容,系统不得不将这个对象放弃,再重新生成第二个新的对象str1,并重新申请一个新的内存空间,虽然 str1 指向的内存地址是同一个,但对象已经不再是同一个了
2、String类解析
String 类被 final 修饰,所以String对象是不可变量,String类实现了Serializable,Comparable,CharSequence
2.1、 String的内部创建过程
方法一: 首先使用String的构造方法创建一个字符串
String s = new String("字符串");
debug进入String类中查看其创建该字符串的具体逻辑
//String的构造方法
public String(String original) { //original:"字符串"
this.value = original.value; // value:{字,符,串}
this.hash = original.hash;//hash:0 original:"字符串"
}
这种创建方式会在堆内存中开辟内存空间,用来存放生成的字符数组,让我们来看另一种创建字符串的方法
方法二: 直接赋值创建 String
String s = "字符串"; //在编译期直接在常量池中创建字符串
tips:此处我们需要知道常量池(constant pool)的大致概念:在编译期被确定,并保存在已编译的.class文件中的一些数据,它包括了关于类、方法、接口等中的常量,也包括字符串常量,–常量池是JVM的一块特殊的内存空间。
总结
new String() 创建的字符串不是常量,不能在编译期就确定,所以 new String() 创建的字符串不放入常量池中,它们有自己的内存地址空间。
直接赋值的字符串则是会在编译器确定下来,并存储在常量池中,由于String对象的不可变机制会导致修改 String 时产生大量对象,Java为了更有效的使用内存,常量池在编译期遇见直接赋值的String字符串,会检查池内是否已经存在相同的String字符串,如果有,把新变量的引用指向现有的字符串对象,不会创建任何新的String 常量对象,如果没找到就创建新的。
所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收
2.2、String的不可变
在 String 类的开头有如下定义:
/** The value is used for character storage. */
private final char value[];
定义了一个字符数组,使用final修饰,final修饰的字符数组 char 创建后不可继承,因为String类被final修饰,其内部主要存储字符串的char 数组的访问修饰符为private,禁止用户对String 类进行继承,这些因素确保了String的不可变
3、String常量池问题的例子
转载自CSDN:https://blog.csdn.net/gaopeng0071/article/details/11741027