String 类
String 是不可变类,不可变的意思是 String 类型变量初始化后,其引用指向内存内容不能改变,变量引用可以指向其他内存。
定义一个 String 变量 str,引用指向内存字符串 abc。
变量赋值时,新开辟内存 def 字符串,str 引用指向新对象,原内存内容 abc 不变。
String 类是一个字符串数组的封装类(内部一个 char[] 数组)。数组类型 final private,引用 value 值不可变,外部无法访问。
因此,String 对象本质是指向一个 char 数组内存的引用,设计成 final 不可变类型,一旦 String 对象创建,value 值初始化,指向一块字符数组内存,char[] 引用不可变,String 对象即不可改变。
替换字符串中的某个字符,String 类 replace() 方法,不直接更改 char[] 引用指向内存,而是开辟一块新内存。
创建新 char[] 数组,分配内存,长度和老数组一致,复制,替换,new 一个新 String 类对象,在构造方法,新 char[] 数组赋值 String 类内部 value,返回新 String 引用。
class 文件常量池,在文件中,编译器编译生成字面量和符号引用,未载入内存,字面量是文本字符串,(如 String str = "abc" 中的 abc)。
符号引用是类/接口全限定名,(如 java/lang/String ),变量名称( str ),方法名称和描述符(参数和返回值)。
类加载内存后,class 文件常量池(字面量和符号引用),进入方法区运行时常量池,该常量池区全局共享。
字面量(字符串常量池), jdk1.7 后不再方法区,移到堆中,符号引用如方法名、类全限定名仍然在方法区。
定义一个 String 变量 a,编译后 hello2 是文本字符串,在 class 文件常量池,编译阶段确定 a 的值。
两个字符串字面值,编译时会进行优化(拼接),解析成一个,所以 a2 在编译期由编译器直接解析为 hello2。
反编译 javap -verbose StrClass.class 命令,查看 class 文件常量池。
编译时会检查常量池是否已存在 hello2 字符串,只有一个 #2,String,对应 #22,即 hello2。
此过程会查找字符串常量池是否存在 hello2,若不存在,在堆创建 char[] 数组,创建 String 对象关联 char[] 数组,保存到字符串常量池,最后将a指向这个对象。
编译阶段,不能确定 a3 的值,定义 final 变量 c,字节码替换掉 a4 中的 c 变量,场景和 a2 一致。
(运行时)对象变量初始化,new 一个 StringBuilder 对象,a3 引用指向 toString() 方法在堆内存 new 的 String 对象。a==a4,指向字符串常量池,a3 指向堆内存 new 的 String 对象。
类加载时,在常量池创建对象 hello2,变量 a5,运行时堆内存 new一个 String 对象,字符串 hello2 已经在常量池,#2项,a 引用指向字符串常量池,a5 引用指向堆内存新对象,(a!=a5)。
class 文件常量池,hello2 文本字符。
类加载内存时,在字符串常量池创建一个 hello2 字符串对象。
对象初始化时,new 指令,在堆中再次创建一个对象,变量 a6 引用指向它。
class 文件常量池只有 hello 和 2 字符串,没有 hello2 字符串,当类加载时,在字符串常量池不存在 hello2 对象。
初始化时,new 指令在堆创建两个 String 对象( hello和2 ),通过 StringBuffer 类 append() 方法,toString() 方法在堆内存中 new 一个 String 对象 (hello2),a7 引用指向它。
前一节的变量 a3=b+2 赋值时,class 字节码中定义了一个 StringBuilder 类,调用两次 append() 方法,依次添加 b 和 2 ,即 hello 和 2,一次 toString() 方法,堆内存创建对象。
StringBuffer 和 StringBuilder 区别是线程安全。
StringBuffer 通过 char[] 数组保存数据,每一个 append() 方法的新增数据在 char[] 数组保存,支持不同类型,boolean 类型保存4或5个字符 (true/false),字符串将每个字符保存,StringBuffer 类可以对字符串进行修改,进行字符串拼接时,不会产生新对象,直接对 char[] 数组进行操作更改。
几乎所有的字符操作方法都 synchronized 同步,该类线程安全。
toString() 方法,创建一个 String 对象,关联 char[] 数组。
任重而道远