字节码底层分析String

String

特性

  1. 不可变性:不可变性也就是 如果创建了一个String对象,进行改变那么就是再创建了一个对象,而不是在原有的改变。
  2. jdk8之前内部存储定义的是char类型数组
  3. jdk9以后是定义的byte类型数组存储,可以更好的节省了空间。
  4. 字符串常量池在jdk1.7(含7)以后都是存储在堆空间中的。

字符串常量池

  1. String pool 底层也就是HashTable
  2. 所以字符串常量池是不可重复的
  3. 如 String s = “abc” s2 =“abc”. 在栈中其实引用的是同一个地址(编译优化)
  4. jdk1.6以前 HashTable 长度默认值1009 ,jdk7默认为 60013, jdk8以后设置长度最低要求1009

参数设置

-XX:StringTableSize=*

链表短的话会影响效率

实战

可编译看字节码,以下都是基于jdk1.8以后进行说明

声明:1.字面量创建String 那么会在字符串常量池中添加一个空间,但是堆空间不会有地址;

声明:2.new 方式创建String 那么会在字符串常量池中添加一个空间,并且在堆中开辟一个空间,并且引用堆空间的地址

声明:3.两个字面量拼接,那么会编译阶段就会进行编译优化如String c = "a"+"b";编译期间会默认为String c = "ab",不会再字符串常量池中分别开辟空间

声明:4.在String c = new String("a")+new String("b")相加是不会在字符串常量池中开辟新的空间的,c只是引用

public void test(){
        String s = "javaHeap";
        String s1 = "java";
        String s2 = "heap";
        String s3 = s1 + s2;
        /**
         * 因为编译时 s1 s2 相当于在字符串常量池中创建对象,不知道其中的值,需要引用地址
         * 当赋值时,那么底层会使用 StringBuilder 的append 方法进行拼接,是引用了两个地址,进行赋值,组成新的对象,并且字符串常量池中是没有"a、javaHeap"
         */
        boolean result = s == s3; //false
    }

public void test2(){
        String s = "javaHeap";
        final String s1 = "java";
        final String s2 = "heap";
        String s3 = s1 + s2;
        /**
         *  final在编译期就已经确定下来了值,在进行字符串拼接时会进行 编译优化 String s3 = "javaHeap"
         */
        boolean result = s == s3; //true
    }
public static void test3(){
        String s = new String("javaHeap");
        /**
         * 在内存中创建了5个对象 细致的说6个
         * 1.new 在堆中
         * 2.“字符串”在字符串常量池中
         * 3. + 变量拼接 创建了StringBuilder
         * 外加:StringBuilder 中的toString方法,底层也就是new String();但是不会在常量池中创建
         */
        String s2 = new String("java") + new String("Heap");
    }
public static void test4(){
        /**
         * 字面量和new 的区别
         * 1. 字面量会在字符串常量池中 放入,new对象也会在常量池中放入"javaHeap"
         * 2. 字面量不会在堆中开辟空间,而new会在堆中开辟空间
         */
        String b = new String("javaHeap");//返回的是堆空间中的地址
        String a = "javaHeap";
        System.out.println(a==b);//false
    }

intern方法

简介

Intern方法:查看字符串常量池中是否有 , 如果有,那么返回字符串常量池中的引用,如果没有将会查看堆中是否有数据,有将会引用对象地址,没有那么创建字符串,放入常量池。

为什么使用intern?

:降低内存的大小,提高的运行的速度,会自动释放内存,会引用常量池中的数据

实战详解

public static void test(){
        /**
         *  内存结构详解:
         *      new String 是在堆中创建了对象,并且在字符串常量池中创建了字面量,
         *      第二行:(在创建字面量时 先查看了堆中是否有对象的引用,如果有那么就不会进行创建,之间在字符串	常量池中引用了堆中的地址【节省空间】)
         *      String s = "javaHeap";
         *      字面量:只会在常量池中 创建常量。
         *
         *      所以在比较时 new 在常量池是对象引用地址,而字面量是值(或者说地址)所以false
         */
        String s2 = new String("javaHeap");
        s2.intern();
        String s = "javaHeap";
        System.out.println(s==s2);//false
    }

public static void test2(){
        /**
         *  内存结构详解:
         *      这里在进行第一行代码时 结构(创建了6个对象,最后在堆中生成了对象s ="javaHeap" 变量池中没有生成)
         *        第二行:在变量池中生成
         *        第三行:直接引用变量池
         *
         */
        String s = new String("java") + new String("Heap");
        s.intern();
        String s2 = "javaHeap";
        System.out.println(s==s2);//true
    }
//-------------------------------------------------------------------------------------------------
public static void main(String[] args) {
        String str2 = new String("xin") + new String("cen");
        //String str2 = new String("a");
        String intern = str2.intern();
        String str = "xincen";
        System.out.println(intern==str);//true 比较串常量池中的地址
        System.out.println(str2==str);//false 比较了堆中的地址
    }

面试点提问+源码

问如果在字符串拼接的时候一定是用的StringBuilder么?

答:不是 因为final 修饰的不是

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值