【源码解析】Java8-String

- #### String是Immutable(不可变的)
  1. String源码及分析:

    类定义:

    1
    public final class String {}

    变量定义:

    1
    2
    3
    4
    5
    6
    7
    /** The value is used for character storage. */

    private final char value[];

    /** Cache the hash code for the string */

    private int hash; // Default to 0

    hashCode计算:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
    char val[] = value;

    for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
    }
    hash = h;
    }
    return h;
    }

    由源码可以看出hash值初始化时是0,当获取过一次之后hashCode就会被计算出来,然后被缓存了下来,随String一块不再变了,也正是因为此,喜欢吧String作为HashMap的key

    hashCode计算有个问题:为什么需要一个中间变量h ?

    答:没有临时变量是线程不安全的,因为多线程访问下,如果没有h,当一个线程进行计算时,第二个线程进来,此时hash不为0则直接返回此时错误的值。

    String保持不可变性采取了哪些措施?

    • value[] 使用 private final 修饰
  • 构造函数中复制实参的值给 value[]
    • 不对外提供任何修改 value[] 值的方法
  • 需要返回 String 的方法,绝不返回原对象,都是重新 new 一个 String 返回
  1. String对象的创建

    String Pool(字符串池):

    • 定义:Java为String提供了特殊的存储机制,叫String intern pool,全局共享的,存储的是队中字符串实例的引用而不是存储实例本身,在方法区

    • 哪些对象会放在:1.字面值字符串 2.字符串赋值常量表达式3.使用intern方法对String对象操作返回的String对象

      举栗子:

      1
      2
      3
      4
      5
      6
        String st1 = "yveshe1";
      String st2 = new String("yveshe2");
      String st3 = "a"+"b";
      String st = st1 + "hello";
      String internStr = st.intern();
      System.out.println(st == internStr);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    1. 字面值字符串有:yveshe2hello,a,b
    2. 字符串赋值表达式:st1 = "yveshe1" ,st3 = "a"+"b";
    3. 使用intern方法的有:st1 = yveshe1hello

    ​ 其中st1在常量池 ,st2不在常量池 ,st3在常量池,st不在常量池

    internStr1.6之前在常量池,1.6之后使用的st的实际地址,只在常量池中保存了引用

    String对象的创建:

    1. String s1 = "aaaa";

    Java虚拟机首先在字符串池中查找是否存在值为”aaaa“这个对象,如果有则不再创建新的对象,直接返回已存在的对象的引用;如果没有则先创建这个对象,放在字符串池中,再将它引用返回

    2. String s1 = new String("aaaa");

    创建了两个对象,一个是字面量aaaa创建的String对象,在String Pool中,另外一个是new产生的String对象,在Java Heap

    3. 使用+操作符号创建String对象

    - String s1 = "yves" + "he";
    System.out.println(s1 == "yveshe");

    编译会变成String s1 = "yveshe"

    - String s1 = "yves";
    String s2 = s1 + "he";
    System.out.println(s2 == "yveshe");

    编译成如下:

    String s1 = "yves";
    String s2 = (new StringBuilder(String.valueOf(s1))).append("he").toString();
    System.out.println(s2 == "yveshe");

    4. intern()方法的用途

    String s = new String("YvesHe").intern();
    System.out.println(s == "YvesHe");

    结果为true

    作用有两个,1. 把字符串字面量放入常量池 2. 返回常量的引用

    5. String.ValueOfInteger.toString和“”+i

    前两个没啥区别,最后会new 一个String

参考:https://juejin.im/post/5ca5c51451882544114cdc95

https://blog.csdn.net/u011479200/article/details/83384215

https://www.cnblogs.com/fangfuhai/p/5500065.html