Java String类相关知识梳理(含字符串常量池(String Pool)知识)

时间:2022-08-24 17:23:01

目录

1. String类是什么

  1.1 定义

  1.2 类结构

  1.3 所在的包

2. String类的底层数据结构

3. 关于 intern() 方法(重点)

  3.1 作用

  3.2 字符串常量池(String Pool)

4. String类所用的连接符

5. String类的主要作用(简)

正文

1. String类是什么

  1.1 定义

  String类表示字符串。Java程序中的所有字符串都是这个String的实例,比如"abc"。字符串为常数,它们的值在创建之后不能更改。因为字符串对象是不可变的,避免了现线程安全问题的出现,所以可以共享它们。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  问:“字符串为常数,它们的值在创建之后不能更改”——①这句话的具体表现(从String的使用角度出发)?②为什么要一经创建就不可更改?③怎么做到一经创建就不可更改的?

    答:

    ①通过调用String的方法我们可以发现,String并未真正提供“字符串的修改”方法,诸如replace这类的字符串替换方法,也只是创建一个新的字符串来替换,而非在原字符串上进行替换;

    ②这个问题从字符串的使用场景来解释比较好理解:从用户使用时的安全性考虑(线程安全),八种基本数据类型的“复制”是再新创建一份相同的数据,而String其实也相当于是一种基本的数据类型,只是它有引用,比较复杂一些,所以字符串要一经创建就不能更改。

    ③封装:虽然String的底层数据结构是char数组(数组的内容是可以更改的),但是,String将该字段声明为private,且并不对外暴露修改数组内容的方法。

  1.2 类结构

public final class String implements java.io.Serializable, Comparable<String>, CharSequence{……}

  ① final:String类不能被继承;

  ② Serializable:可序列化;

  ③ Comparable<String>:用于字符串之间的比较;

  1.3 所在的包:java.lang

  java.lang包是java语言的核心,它提供了java中的基础类。包括基本Object类、Class类、String类、基本类型的包装类、基本的数学类等等最基本的类。

2. String类的底层数据结构

private final char value[];//不可变的字符数组

  问1. 如果说String的底层数据结构是“不可变的char数组”,那不应该是声明为“ private final char[] value;”吗?

    答:这也是数组的一种声明方式,只是比较少见、少用,或许因为历史原因所以String保留使用着这种不常用的数组声明方式。

  问2. 不可变的字符数组的声明只能保证String对象的引用不可变,而用了char数组来作为存储结构,只能保证字符串一经声明其长度不可变,但是数组中存储的内容时可以改变的,从何保证字符串一经声明就不能再变呢?

    答:见 1.1的第③点;

  

3. 关于 intern() 方法(重点)

  3.1 作用:该方法用于返回字符串对象的规范表示形式。

public native String intern();// native方法,看不到具体实现。

  当调用intern方法时:

    ①如果字符串常量池中已经包含了一个由equals(object)方法确定的String对象的字符串,则返回池中的字符串。

    ②否则,将这个 String对象添加到池中(这是JDK1.8中intern()方法的注释给出的说明,但通过下面的测试,我认为是“将这个String对象的字符串内容添加到池中”会更好理解),并返回对这个String对象的引用。

    @Test
public void test() { // 池中没有相应的字符串内容:
String s1 = new String("hello");// 在堆中生成"hello"字符串对象
String s2 = s1.intern();// 执行“s1.intern()”时,String Pool中没有"hello",会直接先将s1对象的字符串内容“hello”复制到池中
System.out.println(s1 == s2); // false,s1指向堆中的对象,s2指向字符串常量池中的字符常量。
System.out.println(s1.intern()); // hello // 池中有:
String s3 = "world"; // 直接在String Pool中生成"world"字符串
String s4 = s3.intern(); // 从池中拿"world"字符串返回给s4
System.out.println(s3 == s4); // true
}

  3.2 字符串常量池(String Pool)

  字符串常量池最初是空的,由类 String私下维护。

  (1)在哪儿

    在JDK6及之前版本:字符串常量池是放在永久代中;

    在JDK7版本中:字符串常量池被移到了堆中。

  (2)数据结构

    在HotSpot VM中字符串常量池是通过一个StringTable类(一个Hash表,并非java实现类,所以知道即可)实现的;这个StringTable在每个HotSpot VM的实例中只有一份,被所有的类共享;

  (3)存放的内容

    在JDK6及之前版本:String Pool里放的都是字符串常量;

    在JDK7.0中:由于String.intern()发生了改变,因此String Pool中也可以存放放于堆内的字符串对象的引用。

  (4)特性:常量池中不存在两个相同的对象

  (5)字符串常量池存在的意义(为什么要有它?):避免字符串常量的重复创建,节省内存空间。

  (6)什么情况下生成的字符串才会被放到String Pool中?

    ① 字面量:代码中直接使用双引号引着的字符串都会被存储到字符串常量池中,如:String abc = "abc";;

    ② 调用String的 intern()方法,如果字符串内容是字符串常量池中没有的,那么会先复制一份内容到字符串常量池中;

4. String类所用的连接符

  Java语言为“+”连接符以及将对象转换为字符串提供了特殊的支持:

  字符串对象可以使用“+”连接其他对象。其实字符串连接是通过StringBuilder(或 StringBuffer)及其 append()方法 实现的。

  字符串转换是通过 toString()方法实现的,该方法由Object定义,并由Java中的所有类继承。

5. String类的主要作用(简) 

  ①检查序列的单个字符、
  ②比较字符串、
  ③搜索字符串、
  ④提取子字符串
  ⑤创建一个字符串的副本的方法,
  ⑥大小写转换;
  ⑦更多;