JDK源码之String类解析

一 概述

String由final修饰,是不可变类,即String对象也是不可变对象.
这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象
主要考虑以下原因:

  1. 为了实现字符串池(提升效率)
    只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。
    但如果字符串是可变的,那么String interning将不能实现,因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
  2. 为了线程安全
    同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的
    String被广泛用作许多java类的参数,例如网络连接、打开文件等。如果对string的某一处改变一不小心就影响了该变量所有引用的表现,则连接或文件将被更改,这可能导致严重的安全威胁。
  3. 为了实现String可以创建HashCode不可变性
    因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这样更有效率。
    因为当向集合中插入对象时,是通过hashcode判别在集合中是否已经存在该对象了(不是通过equals方法逐个比较,效率低)
    这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串

二 常量池

Java中的常量池分为三种类型:

  1. 类文件中常量池(The Constant Pool):
    存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)
    • 字面量:
      1. 文本字符串
      2. 八种基本类型的值
      3. 被声明为final的常量等;
    • 符号引用:
      1. 类和接口的全限定名(Fully Qualified Name)
      2. 字段的名称和描述符(Descriptor)
      3. 方法的名称和描述符
  2. 运行时常量池(The Run-Time Constant Pool)
    诞生时间:JVM运行时
    内容概要:class文件元信息描述,编译后的代码数据,引用类型数据,类文件常量池。
    所谓的运行时常量池其实就是将编译后的类信息放入运行时的一个区域中,用来动态获取类信息。
    运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,
    也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
  3. String常量池(String Pool)
    • JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,即字符串池(String Pool)。字符串池由String类私有的维护
      JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代.
    • JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
      JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)
    • 在1.6中,常量池在方法区,intern()会把首次遇到的字符串实例复制到永久代中,返回的也是这个永久代中字符串实例的引用;
      而在1.7,1.8中,String 的 intern 方法不会再复制实例到常量池中,如果不存在,则这个String肯定在堆中,则将当前实例的引用复制到实例中并返回该引用,如果存在则直接返回该实例
    • 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,jdk6中默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。
      字符串常量由一个一个字符组成,放在了StringTable上。。而在java 7中一开始就是可以配置的(至少在java7u02中是可以配置的)。你需要指定参数 -XX:StringTableSize=N, N 是字符串池 Map 的大小。
      确保它是为性能调优而预先准备的大小,jdk8中大小已经增大到60013

三 实现接口

1 java.io.Serializable

2 Comparable

3 CharSequence

四 源码解析

1 属性

2 构造器

2.1 StringUTF16工具类分析

3 内部类

4 实现接口的方法

常用API

五 总结

1 intern 方法解析

2 常见创建几个对象问题

3 关于 + 拼接创建对象问题

4 final修饰String问题

猜你喜欢

转载自www.cnblogs.com/houzheng/p/12099302.html