1. 创建 String
有哪几种方式
- 常量定义:
String name = "你真棒";
new
创建:String name = new String("你真棒");
+/+=
运算符:String name = "你"; name += "真棒";
2. 怎样理解 String
- 在 Java 9 之前,
String
类内部用一个字符数组表示字符串:private final char value[];
- 使用
String
构造方法时,String
会根据参数新创建一个数组,并复制内容,而不会直接用参数中的字符数组
3. 怎样理解 Java 中 String
的编码转换
- 在 Java 9 之前,
String
内部是按 UTF-16BE 处理字符的。对 BMP 字符,使用一个char
,两个字节;对于增补字符,使用两个char
,四个字节 - 不同编码可能用于不同的字符集、使用不同的字节数目、以及不同的二进制表示
4. 如何处理这些不同的编码,这些编码与 Java 内部表示之间如何相互转换呢
- Java 使用
Charset
类表示各种编码 - 除了通过 String 中的方法进行编码转换,
Charset
类中也有一些方法进行编码/解码。重要的是,Java 的内部表示与各种编码是不同的,但可以相互转换
5. 怎样理解 String
的不可变性
- 与包装类类似,
String
类也是不可变的,即:对象一旦创建,就没有办法修改了String
类也声明为了final
,不能被继承。内部字符数组value
也是final
的,初始化后就不能再变了String
类中提供了很多看似修改的方法,其实方法内部都是通过创建新的String
对象来实现的,原来的String
对象不会被修改
- 与包装类类似,定义为不可变类,程序可以更为简单、安全、容易理解
- 如果频繁修改字符串,而每次修改都新建一个字符串,那么性能太低。这时,应该考虑 Java 中的
StringBuilder
和StringBuffer
这两个类
6. 怎样理解字符串常量
- Java 中的字符串常量是非常特殊的,除了可以直接赋值给
String
变量外,它自己就像一个String
类型的对象,可以直接调用String
的各种方法- 实际上,字符串常量就是
String
类型的对象。在内存中,它们被放在一个共享的地方,这个地方称为字符串常量池 - 字符串常量池保存所有的常量字符串,每个常量只会保存一份,被所有使用者共享
- 实际上,字符串常量就是
- 当通过常量的形式使用一个字符串的时候,使用的就是常量池中的那个对应的
String
类型的对象 - 如果不是通过常量直接赋值,而是通过
new
创建,则就是两个对象了
7. String
类中 hashCode()
方法怎样计算 hash
值
- 看
hashCode()
方法源码可知,hash
是一个私有的整型变量。hash
变量缓存了hashCode()
方法的值,第一次调用hashCode()
方法的时候会把结果保存在hash
这个变量中,以后再调用就直接返回保存的值 - 如果缓存的
hash
值不为 0,就直接返回了,否则根据字符数组中的内容计算hash
- 计算
hash
的算法是:s[0] * 31^ (n-1) + s[1] * 31^ (n-2) + …… + s[n-1]
- 分析:
s
表示字符串,s[0]
表示第一个字符,n
表示字符串长度,s[0] * 31^ (n-1)
表示第一个字符的值乘以 31 的 (n-1) 次方
- 分析:
8. 计算 String
类的 hash
,为什么要用上面的那个公式
- 使用这个公式,从数学的角度显而易见
- 可以让
hash
值与每个字符的值有关,也与每个字符的位置有关
9. 计算 String
类的 hash
的公式为什么用数字 31
- 使用 31 大致有两个原因
- 一方面可以产生更分散的散列,即不同字符串
hash
值也一般不同 - 另一方面是计算效率也比较高,
31 * n
与32 * n - n
,即(n << 5) - n
等价,可以用更高效率的移位和减法操作代替乘法操作
- 一方面可以产生更分散的散列,即不同字符串
- 在 Java 中,普遍使用以上思路来实现
hashCode()
方法
10. 什么是正则表达式
- 正则表达式可以理解为一个字符串,但表达的是一个规则,一般用于文本的匹配、查找、替换等
- Java 中有专门的类(如
Pattern
和Matcher
)用于正则表达式,但对于简单的情况,String
类提供了更为简洁的操作
11. Java 9 对 String
的实现做了哪些优化
- 在 Java 9 中,
String
的内部不再是char
数组,而是byte
数组 - 如果字符都是
ASCII
字符(128 个),它就可以使用一个字节表示一个字符,而不用 UTF-16BE 编码,节省内存