String 拼接值的比较

参考下面代码和说明:

	@Test
    public void test() {
        /**
         * String str1= “abc”; 在编译期,JVM会去常量池来查找是否存在“abc”,
         * 如果不存在,就在常量池中开辟一个空间来存储“abc”;
         * 如果存在,就不用新开辟空间。然后在栈内存中开辟一个名字为str1的空间,来存储“abc”在常量池中的地址值。
         *
         * String str2 = new String("abc") ;
         * 在编译阶段JVM先去常量池中查找是否存在“abc”,
         * 如果过不存在,则在常量池中开辟一个空间存储“abc”。
         * 在运行时期,通过String类的构造器在堆内存中new了一个空间,
         * 然后将String池中的“abc”复制一份存放到该堆空间中,
         * 在栈中开辟名字为str2的空间,存放堆中new出来的这个String对象的地址值。
         * 不论new String这种方式在常量池是否创建对象,它指向的始终是堆中的对象。
         * 堆中对象指向字符串常量池中的”abc“/或者说堆中对象又存有字符串常量池中"abc"的引用地址
         */
        String s1 = "Programming";
        String s2 = new String("Programming");
        String s3 = "Program";
        String s4 = "ming";
        /**
         * 常量加常量
         * 编译器自动优化成 "Programming";
         */
        String s5 = "Program" + "ming";
        /**
         * 变量加变量==变量加常量
         * 变量加常量会new一个Stringbuilder并且调用Stringbuilder.appen方法将他们拼接在一起
         * String s6 = s3 + s4;
         * 等价于String s6 = s3 + "ming";String s6 = "Program" + s4;
         * 等价于
         * StringBuilder s = new StringBuilder();
         * s.append("Program");
         * s.append("ming");
         * String str = stringB.toString();
         * StringBuilder.toString 等价于 new String() 括号里是StringBuilder的值"Programming"
         */
        String s6 = s3 + s4;

        StringBuilder s7 = new StringBuilder();
        s7.append(s3);
        s7.append(s4);
        String s8 = s7.toString();
        System.out.println(s6 == s8);//false

        /**
         * 通过字面量赋值创建字符串(如:String s=”string”)时,会先在常量池中查找是否存在相同的字符串,
         * 若存在,则将栈中的引用直接指向该字符串;
         * 若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
         *
         */
        System.out.println(s1 == s2);//false
        System.out.println(s1 == s5);//true
        System.out.println(s1 == s6);//false
        System.out.println(s1 == s6.intern());//true
        /**
         * s2在堆中
         * s2.intern()在字符串常量池中
         * new String()都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中并返回指向该常量的引用。
         */
        System.out.println(s2 == s2.intern());//false

        /**
         * String s12 = s9 + s10;等价于 "a"+"b"
         * 编译期优化后 直接赋值给s12 = "ab"
         *
         * 字符串拼接操作不一定使用的是stringBuilder!
         * 如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非stringBuilder的方式。
         *
         * 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。
         * 在linking准备阶段就对静态变量进行默认值初始化,如果是有final修饰的就显示初始化了
         */
        final String s9 = "a";
        final String s10 = "b";
        String s11 = "ab";
        String s12 = s9 + s10;
        String s13 = s9 + "b";
        System.out.println(s11 == s12);//true
        System.out.println(s11 == s13);//true
    }

String.intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。当通过语句str.intern()调用intern()方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在则直接返回常量池中相应Strnig的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。因此,只要是等值的String对象,使用intern()方法返回的都是常量池中同一个String引用,所以,这些等值的String对象通过intern()后使用==是可以匹配的。

变量加变量==变量加常量 字节码指令说明图
在这里插入图片描述
注意
字符串拼接操作不一定使用的是StringBuilder
如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。在linking准备阶段就对静态变量进行默认值初始化,如果有final就显示初始化了。如上述代码中s12的示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值