Java面经--String系列

97 阅读3分钟

blog.csdn.net/u011541946/…
www.cnblogs.com/xuxinstyle/…

Java的String涉及到几种形式

  1. 堆上字符串, 用new String(), StringBuilder/StringBuffer.toString 创建的字符串
  2. 常量字符串(字符串字面量), 用""直接声明的字符串

对c++比较了解的可能有这样一个概念 "C++鼓励使用常量(字面量是常量的一种),是因为编译器对常量有比较大的优化"。对于 java也一样。

字符串有以下形式

  1. 字面量字符串拼接, "aaa" + "bbb" + "ccc" 会触发编译器优化,成一个字面量串 "aaabbbccc"
  2. 堆上字符串和其他字符串的拼接, "aaa" + new String("bbb") 本质上是一个语法糖,编译器会将其替换成StringBuilder
  3. 字符串intern(), 本质上是获取常量池里的字符串,具有"没有则创建"语义
  4. new String() 创建的字符串, 位于堆上
  5. "aaa" 字面量字符串,位于常量池。
  6. 对一个字面量字符串调用intern() 算啥? e.g. "aaa".intern() java会给出一个warning, 因为如此举动如同脱裤子放屁。我们对intern()的需求是因为线上可能有一些用户传入的字符串,这些是运行时的内容,我们希望把运行时的字符串缓存在常量池,而不是每个对象都占用堆上的空间。尽管"aaa".intern()没有啥意义,但注意: 由于调用intern()后,这个对象就无法被常量优化,实际上对c++,我们可以将其声明为constexpr让其享受编译器对常量的优化,但java显然做不到。因此 "aa".intern() + "b" 就不等同于 "aab" 个人理解是因为编译器不会把"aa".intern() 视为常量,因此其 + 操作是用stringbuilder做的,从而导致最终"aab"位于堆上(待考证)

字符串的比较

== 比较字符串的地址是否相同 equals() 比较两个串 per-char 是否相同。如果字符串只涉及到常量池,那么"equals()相同的所有串"都是同一个副本

因此,我们对上面的字符串分个类

  1. 在堆上的字符串 {2, 4}
  2. 在常量池的字符串{1, 3, 5}
  3. 尽管是常量, 但编译器不认为是常量 {6}

如果两个字符串都在常量池,那么equals() 返回true, == 就返回true。{22, 24, 44}

如果一个在堆, 一个在常量池. 那么equals() 返回true, == 就不一定返回true。{12, 32, 52, 14, 34, 54}

如果一个在堆, 一个也在堆. 那么equals() 返回true, == 就不一定返回true。{11, 33, 55, 13, 15, 35}

一共有15种组合。

唯一需要注意的是,对字面量intern()后的对象调用 + ,不走编译器对字符串常量加法的优化。。。

字符串拼接

  1. 字面量 + 字面量 == 编译期优化,拼接后的字符串在常量池
  2. 字面量.intern() + 字面量,走stringbuilder,拼接后的字符串在堆上
  3. new String() + 字面量,走stringbuilder,拼接后的字符串在堆上
  4. new String() + new String() 走stringbuilder,拼接后的字符串在堆上