Java String 类解析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/OOC_ZC/article/details/83893681

String对象是不可变的

在这里插入图片描述
String 被声明为 final,因此它不可被继承。内部使用 char 数组存储数据,该数组被声明为 private final char value[];,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。String类中每一个看起来会修改String值的方法实际上都创建了一个全新的String对象。

String 不可变的优势

  • 因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
  • 如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。(多个引用指向一个对象)
  • String 经常作为参数,String 不可变性可以保证参数不可变。
  • String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

String Pool (字符串池)

  • JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是字符串池(String Pool),字符串池由String类私有的维护。
  • 字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。
  • 每一个字符串常量都是指向一个字符串类实例的引用。字符串对象有一个固定值。字符串常量,或者常量表达式中的字符串都使用方法 String.intern()进行保留来共享唯一的实例。
  • 字符串池中维护了共享的字符串对象,这些字符串不会被垃圾收集器回收。
  • 在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

String.intern() 方法

  • 一个初始为空的字符串池,它由类String独自维护。当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。
  • 对于任意两个字符串s和t,当且仅当s.equals(t)为true时,s.intern() == t.intern()才为true。
  • 所有字符串常量和表达式中的字符串常量(编译时期已经确定)都被使用了intern()方法。即已被加入到了String Pool中。
  • intern() 是Native函数。
    在这里插入图片描述

字符串池的测试:

在这里插入图片描述

其中new String("abc");

  • 使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 “abc” 字符串对象)。
  • “abc” 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 “abc” 字符串字面量;
  • 而使用 new 的方式会在堆中创建一个字符串对象。
  • 虽然str与str1指向两个对象,但都由"111"这个字符串对象构造而来,两个对象的value[]指向同一个char数组(与字符串池中"111"的value[]指向也相同)。

public String(String str) 构造函数的源代码:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/OOC_ZC/article/details/83893681