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
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我橘子超酸

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

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

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

打赏作者

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

抵扣说明:

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

余额充值