String.intern()方法、str = new String(““)、 str =““等浅析

下述均基于自己理解,有错误之处请大佬指正!
参考:

  • https://blog.csdn.net/seu_calvin/article/details/52291082
  • https://blog.csdn.net/qq_39736597/article/details/113452965?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.control
  • https://www.jianshu.com/p/cf78e68e3a99

关于其中
String s = new String(“1”);
这段代码的理解:“1"是字面量,会从类常量池加载到运行时常量池,在第一次遇到他时进入字符串常量池【此处参考https://www.jianshu.com/p/cf78e68e3a99:3.String"字面量” 是何时进入字符串常量池的?】此处遇到1,即把他放入到字符串常量池中,然后又利用字符串常量池中的"1" 在堆中new了一个全新的对象s。
这种理解与同时在常量池与堆中创建对象 并不会影响对代码最终结果的判断

尝试理解下面的代码

package com.company;

/**
 * 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
 *
 * 在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
 *
 * 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)
 *
 * intern:
 * 在JDK6中,常量池在永久代分配内存,永久代和Java堆的内存是物理隔离的,执行intern方法时,如果常量池不存在该字符串,虚拟机会在常量池中复制该字符串,并返回引用,所以需要谨慎使用intern方法,避免常量池中字符串过多,导致性能变慢,甚至发生PermGen内存溢出。
 * 在JDK7中,常量池已经在Java堆上分配内存,执行intern方法时,如果常量池已经存在该字符串,则直接返回字符串引用,否则复制该字符串对象的引用到常量池中并返回,所以在JDK7中,可以重新考虑使用intern方法,减少String对象所占的内存空间。
 */
public class Main {
    public static void main(String[] args) {
        int i =1;
        //1
        String str1 = "Java";//Class常量池->方法区的运行时常量池->遇到"Java"且字符串常量池中没有"Java"->在堆中创建"Java"并将其引用存放到字符串常量池中
        System.out.println(i++);
        System.out.println(str1.intern() == str1);//true 常量池中的"Java"与str1指向同一对象
        //2
        String str2 = new String("hello");//利用常量池中的"hello"在堆中new一个新的"hello"
        System.out.println(i++);
        System.out.println(str2.intern() == str2);//false,常量池中的"hello"与str2不是同一对象
        //3
        String ts = new String("hello");
        System.out.println(i++);
        System.out.println( str2 == ts);//false ts为在堆中新new出来的
        //4
        String str3 = ts + "Java";//利用StringBuilder连续两次append将ts与"Java"拼接,然后利用toString方法 在堆中new出一个新的字符串
        System.out.println(i++);
        System.out.println(str3.intern() == str3);//true intern方法去字符串常量池中寻找"helloJava"->没有找到->将其引用存放到字符串常量池
        //5
        String str4 = "hello" + "Java1";//在编译过程中进行优化 等价于 String str4 = "helloJava";
        System.out.println(i++);
        System.out.println(str4.intern() == str4);//true,表明str4是常量池的,也从侧面表明在编译的时候已经做了相加的操作了

        String s1 = new String("1");//执行完该行 字符串常量池与堆中均存在"1"且不同,s1指向位于堆中的"1",而不是常量池中的"1"(常量池中的"1"本质上也是在堆中)
        String s2 = "1";//字符串常量池中的"1"
        String s3 = s1.intern();//字符串常量池中的"1"
        //6
        System.out.println(i++);
        System.out.println(s1 == s2);//false
        //7
        System.out.println(i++);
        System.out.println(s2 == s3);//true
        //8
        System.out.println(i++);
        System.out.println(s1 == s3);//false

        String s4 = new String("1") + new String("1");//在堆中new出来一个"11"
        s4.intern();//在字符串常量池中查找是否有"11"->未找到->将引用s4保存到字符串常量池
        String s5 = "11";//字符串常量池中存在"11",将字符串常量池中的"11"即s4赋值给s5
        //9
        System.out.println(i++);
        System.out.println(s4 == s5);//true

        String t1 = new StringBuilder().append("String").append("Test").toString();
        //10
        System.out.println(i++);
        System.out.println(t1.intern() == t1);//true 在字符串常量池中查找是否有"StringTest"->未找到->将引用t1保存到字符串常量池->返回t1

        String st1 = new StringBuffer("计算机").append("shuju").toString();
        String st2 = new StringBuffer("计算机").append("shuju").toString();
        //11
        System.out.println(i++);
        System.out.println(st1.intern() == st1);//true
        //12
        System.out.println(i++);
        System.out.println(st2 == st2.intern());//false 在字符串常量池中查找是否有"计算机shuju"->找到->返回常量池中的值即st1
        //13
        System.out.println(i++);
        System.out.println(st1 == st2.intern());//true


        String tr1 = new String("xx");//在在堆中创建一个"xx"->将其引用存放到常量池->利用常量池中的"xx"在堆中重新创建一个新的"xx"
        tr1.intern();//在字符串常量池中查找是否有"xx"->找到->返回常量池中的值即tr1
        String tr2 = "xx";
        //14
        System.out.println(i++);
        System.out.println(tr1 == tr2);// false tr1是后来创建的,tr2是常量池中的

        String tr3 = new String("1x") + new String("1");
        tr3.intern(); //此处如果注释掉则会将下面的"1x1"即运行时常量池中的"1x1"加载到字符串常量池,如果不注释掉则会将上面在堆中生成的"1x1"加载到字符串常量池
        //【此处参考https://www.jianshu.com/p/cf78e68e3a99:3.String"字面量" 是何时进入字符串常量池的?】
        String tr4 = "1x1";
        //15
        System.out.println(i++);
        System.out.println(tr3 == tr4);//不注释:true 注释:false
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我橘子超酸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值