目录
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类的主要作用(简)
①检查序列的单个字符、
②比较字符串、
③搜索字符串、
④提取子字符串
⑤创建一个字符串的副本的方法,
⑥大小写转换;
⑦更多;