0%

Java 常用基础类(二):剖析 String

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 中的 StringBuilderStringBuffer 这两个类

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 * n32 * n - n,即 (n << 5) - n 等价,可以用更高效率的移位和减法操作代替乘法操作
  • 在 Java 中,普遍使用以上思路来实现 hashCode() 方法

10. 什么是正则表达式

  • 正则表达式可以理解为一个字符串,但表达的是一个规则,一般用于文本的匹配查找替换
  • Java 中有专门的类(如 PatternMatcher)用于正则表达式,但对于简单的情况,String 类提供了更为简洁的操作

11. Java 9 对 String 的实现做了哪些优化

  • 在 Java 9 中,String 的内部不再是 char 数组,而是 byte 数组
  • 如果字符都是 ASCII 字符(128 个),它就可以使用一个字节表示一个字符,而不用 UTF-16BE 编码,节省内存
-------------------- 本文结束感谢您的阅读 --------------------