常用基础类(二):剖析 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. 怎样理解 JavaString 的编码转换?
    答:

    • 在 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 * h32 * h - h,即 (h << 5) - h 等价,可以用更高效率的移位和减法操作代替乘法操作。
    • Java 中,普遍使用以上思路来实现 hashCode
  10. 什么是正则表达式?
    答:

    • 正则表达式可以理解为一个字符串,但表达的是一个规则,一般用于文本的匹配、查找、替换等
    • Java 中有专门的类(如 PatternMatcher)用于正则表达式,但对于简单的情况,String 类提供了更为简洁的操作。
  11. Java 9String 的实现做了哪些优化?
    答:

    • Java 9 中,String 的内部不再是 char 数组,而是 byte 数组
    • 如果字符都是 ASCII 字符,它就可以使用一个字节表示一个字符,而不用 UTF-16BE 编码,节省内存