《Java 底层原理》String字符串详解

前言

Java 字符串底层是如何存储的,如何提高性能的,今天就来好好了解一下。

字符串的存储结构

Jvm 有专门的字符串常量池用于存放字符串,存放字符串的数据结构是HashTable。

HashTable的数据结构如下:

看个案例:

public class StringDemo {
    public static void main(String[] args) {
        String a = "11";
        String b = new String("11");

        System.out.println("a的HashCode:"+a.hashCode());
        System.out.println("b的HashCode:"+b.hashCode());

        System.out.println("a==b :"+(a==b));   // 比较的指针地址
        System.out.println("a.equals(b) :"+ a.equals(b));   // 比较的是hashCode
    }
}

运行结果:

通过案例我们来详细说明一下,Jvm如何创建一个String字符串的。

String 字符串会创建多少个Oop(Oop 是指Java 对象在Jvm中的存在形式)?

String a = "11";       

我们可以通过idea 来看创建了多少个Oop。

调式字符串赋值后。 char[] 和 String 都加一了。

说明创建了两个Oop 

char[] 对应 TypeArrayKlass

String  对应  TypeArrayOopDesc

画图说明字符串在Jvm 中的存在形式:

String a = new String ("11");   -- 创建了3和Oop

再来看一下String 拼接的案例

public class StringDemo2 {
    public static void main(String[] args) {
        String s1 = "1";
        String s2 = "2";
        String s3 = s1+s2;
        String s4 = "12";
        System.out.println("s3 == s4: "+(s3 == s4));
    }
}

运行结果:

拼接字符串的实现原理用一句话完美解释:

new StringBuilder(s1).append(s2).toString();    // toString 方法中有一个new String的逻辑。

并且拼接后的字符串是不放入常量池的。 看看toString 的源码

public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

new String(value, 0, count) ,这种方式创建的String 不放入常量池。

那有什么方式可以将拼接的字符串放入常量池吗?答案是肯定的。

public class StringDemo2 {
    public static void main(String[] args) {
        String s1 = "1";
        String s2 = "2";
        String s3 = s1+s2;
        s3.intern();       // 将拼接的字符串放入常量池
        String s4 = "12";
        System.out.println("s3 == s4: "+(s3 == s4));
    }
}

intern 方法就是将拼接的字符串放入常量池。

再来看一个案例:

public class StringDemo2 {
    public static void main(String[] args) {
        final String s1 = "1";
        final String s2 = "2";
        String s3 = s1+s2;
        String s4 = "12";
        System.out.println("s3 == s4: "+(s3 == s4));
    }
}

运行结果:

原因是s1,s2 都是final修饰,表示不会变,那么String s3 = s1+s2; 其实也不会变,所以和 s3 = “12” 等价。   

总结

String 字符串对应数据存放在字符串常量池。

拼接字符串实际就是StringBuilder 拼接。

final 修饰的情况。

intern 方法的作用是 将字符串加入常量池。

posted @ 2021-03-04 15:57  加速丨世界  阅读(1315)  评论(0编辑  收藏  举报