【JavaSE】String类与字符串常量池

文章目录

  • 1.String类的特性
  • 2.String的不可变性
  • 3.字符串常量池
  • 4.String的两种赋值方式
  • 5.String不同的拼接操作

1.String类的特性

  • String: 字符串,使用一对 “” 引起来表示
  • String是一个final类,不可被继承
  • String实现了Serializable接口:表示字符串支持序列化
  • String实现了Comparable接口:表示String可以比较大小
  • String类内部定义了 final byte[] value用于存储字符串数据
  • String具有不可变性

 

2.String的不可变性

当对字符串重新赋值时,需要重新生成指定内存区域赋值,不能使用原有的 value进行赋值。

 
String字符串的可变性,它是怎么实现的?

查看 String类 的源码,我们可以知道,
字符串的底层是通过 byte[] 数组存储的。(在 jdk9 之前,使用的是 char[] 数组)
但是不管是哪种方式存储,它都用了 final关键字修饰。也就是说具有了不可变性。但这里的不可变性指的是地址不可变。真正实现不可变性的是:String类中没有能改变 byte[] 数组中的内容的方法。

final char[] arr = new char[]{1,2,3};
arr[0] = 'a'; // 值可变
arr = new char[]{'1'}; // 地址不可变,因为被 final修饰

String类中,有关改变内容的方法,都是生成一个新的字符串,然后将其返回。

 

3.字符串常量池

字符串常量池不会存储相同内容的字符串。
(不同的JDK版本常量池的位置有所不同,JDK7:字符串常量池的位置在堆内存中)

// 字面量的定义方式
String s1 = "abc"; /* 第一次创建对象,将 "123" 放入常量池 */
String s2 = "abc"; /* 第二次创建对象时,直接将常量池中 "123" 的地址给s2 */
System.out.println(s1 == s2); /* 此时 s1和 s2都指向常量池中的同一个地址 */

 

4.String的两种赋值方式

  • 通过字面量定义的方式

通过此种方式创建的数据声明在字符串常量池中

  • 通过new + 构造器的方式

通过此种方式,此时 str 保存的地址值,是数据在堆空间中开辟空间以后的对应的地址值,String的字符串数据存储在 value数组中,value是一个引用类型,对于 value:

  • 若要创建的字符串在字符串常量池中存在,则 value直接指向常量池中的该字符串
  • 若要创建的字符串在字符串常量池中不存在,则会在字符串常量池中创建该字符串,然后将 value指向常量池中的该字符串

String类的构造方法源码:

说明:在对象创建之前该字符串已经存在于字符串常量池中,并将其地址赋于 value;也就是说 new的方式,是获取了常量池中的字符串的地址;若该字符串在常量池中不存在,也会先在常量池中创建,再赋于 value。真正的字符串值是在字符串常量池中。
public String(String original) {
      this.value = original.value;
      this.hash = original.hash;
}

总之:value是一个引用,String str = new String(“abc”)中的 str也是一个引用,指向堆空间,value则指向常量池。String str = "abc"的方式则是让 str直接指向量池。

 
String str1 = “abc”; 与 String str2 = new String(“abc”);

String str1 = "abc";
String str2 = new String("abc");

【JavaSE】String类与字符串常量池_第1张图片
 
地址值判断:

// 字面量的方式
String str1 = "abc";
String str2 = "abc";
// new + 构造器的方式
String str3 = new String("abc");
String str4 = new String("abc");

System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
System.out.println(str1 == str4); // false
System.out.println(str3 == str4); // false

 

5.String不同的拼接操作

String s1 = "abc";
String s2 = "123";

String s3 = "abc123";
String s4 = "abc" + "123"; // 编译时优化,为常量 "abc123", s4指向常量池
String s5 = s1 + "123"; // 有变量参与, 因此 s5通过 new的方式创建,  s5指向堆空间
String s6 = "123" + s2;
String s7 = s1 + s2;

System.out.println(s3 == s4); // true
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s6); // false
System.out.println(s5 == s7); // false
System.out.println(s6 == s7); // false

String s8 = s5.intern(); // 返回 s5在常量池中的地址
System.out.println(s3 == s8); // true
String str1 = "abc123";
String str2 = "abc";
String str3 = str2 + "123";
System.out.println(str1 == str3);
/* 
*  为 false, str1 指向常量池,str3 中有变量参与拼接,str3 指向堆空间;
*/

final String str4 = "abc";
String str5 = str4 + "123";
System.out.println(str1 == str5);
/*
*  为 true, str1 指向常量池,str4被 final修饰,不可变,为常量,常量与常量拼接在编译	
*  时优化为 "abc123",因此 str5也指向常量池。
*/

你可能感兴趣的:(JavaSE,java)