IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java中String.intern()方法浅记 -> 正文阅读

[Java知识库]Java中String.intern()方法浅记

Java中String.intern()方法浅记

String在Java中是一个比较特殊的存在。String既可以使用字面量进行赋值,也可以使用new进行赋值。

  • 使用字面量进行赋值,会直接放进字符串常量池
  • 如果使用new进行创建对象,会在堆中生辰给一个对象,也会在常量池中存放一份,两者并不相同。

注意:

字符串常量池从jdk7开始,从方法区移到了堆中。静态变量也从方法区中移到了堆中。

概念

使用intern()方法,会先判断字符串常量池中是否已经包含当前的字符串,如果没有的话,则会在字符串常量池中存放一份。在具体的实现中稍有不同。

  • 在jdk6之前(包含jdk6),字符串常量池在方法区中,与堆不在同一个区域,所以字符串常量池中是拷贝了一份字符串的对象,Java堆中的String对象和字符串常量池的String对象不是同一个。
  • 在jdk7之后(包含jdk7),字符串常量池转移到了堆中。当堆中有一个String对象的时候,在调用intern方法时,如果字符串常量池没有这个字符串,则会存放堆中String对象的地址引用,不会像jdk7之前的拷贝一份到字符串常量池中。此时,字符串常量池翠芳的和堆中String对象代表的是一个。

如果有描述不清处的欢迎大家查看《深入了解java虚拟机的》第三版的63页。字符串常量池的迁移查看46页。

代码验证

**环境:**jdk1.8

主要验证的是jdk8,也就是字符串常量池迁移到堆的情况,jdk6之前的情况,感兴趣的可以自己尝试。

测试方法:

第一种情况:

public class InternTest {
    public static void main(String[] args) {
        String str1 = new String("jay,cay");//会在堆中有一个,在字符串常量池中有一个
        str1.intern();//此时这行代码不会往字符串常量池中存放,因为字符串常量池中已经有一个相同值的对象
        String str2 = "jay,cay";
        System.out.println(str1 == str2);
    }
}

测试结果:

false

分析:

在new的时候会在堆中有一个,在字符串常量池中有一个。所以intern方法相当于没有起作用,因为因为字符串常量池中已经有一个相同值的对象

第二种情况:

public class InternTest {
    public static void main(String[] args) {
        String str1 = new String("jay,cay");
        str1.intern();
        String str2 = "jay,cay";
        System.out.println(str1 == str2);

        String str3 = new String("aa") + new String("bb");//字符串常量池中不会有aabb
        str3.intern();//将堆中的aabb的引用存放在字符串常量池中
        String str4 = "aabb";
        System.out.println(str3 == str4);
    }
}

测试结果:

false
true

分析:

由于两个new字符串的拼接,所以在字符串长量池中不会有aabb,下面的intern方法会将堆中的aabb的引用存放在字符串常量池中。这样str3和str4就相同了。

反思:

实际中使用的StringBuilder产生的字符串不在字符串常量池中的多,下面这段代码可以在《深入了解Java虚拟》63页找到。

String str5 = new StringBuilder("计算机").append("软件").toString();
str5.intern();
String str6 = "计算机软件";
System.out.println(str5 == str6);//得到的也是true

特例:

在《深入了解Java虚拟》63页提到了一个特例,就是java这个字符串,使用下面的方式得到的是false,原因是在项目启动的时候默认会加载一个java字符串在字符串常量池。

String str7 = new StringBuilder("ja").append("va").toString();
str5.intern();
String str8 = "java";
System.out.println(str7 == str8);//得到是false

疑惑:待解决

之前遇到过使用junit4的时候,使用下面的代码得到的都是false,而且在main方法中添加org.slf4j.Logger(在intern方法之前),进行打印日志也会得到的都是false,使用的springboot时2.3.1。本次在junit5中测试,使用的spring boot2.6.2,得到的结果,和上面代码得到的结果一致。

测试方法代码如下:

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class InternTest {
    @Test
    public void testIntern(){
        String str1 = new String("jay,cay");
        str1.intern();
        String str2 = "jay,cay";
        System.out.println(str1 == str2);
        String str3 = new String("aa") + new String("bb");
        str3.intern();
        String str4 = "aabb";
        System.out.println(str3 == str4);
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:27:33  更:2022-04-18 17:28:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:59:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码