其他分享
首页 > 其他分享> > 详解String的intern方法

详解String的intern方法

作者:互联网

参考链接:黑马程序员JVM完整教程,全网超高评价,全程干货不拖沓_哔哩哔哩_bilibili

知识补充

常量池

1、常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量
池,并把里面的符号地址变为真实地址

2、程序执行时,常量池中的信息(符号)都会被加载到运行时常量池中,但是加载完之后,这些符号还没有成为java对象,只有执行到具体某一行代码的时候,才会转变为java对象,并将字符常量放进串池(StringTable,是一个哈希表,长度固定且不能扩容)中。

java中的数据类型

java中的数据类型分为基本类型和引用类型

1、java中有八种基本数据类型:

      byte - 1字节

       short - 2字节
       int - 4字节
       long - 8字节,赋值时一般在数字后加上 l 或 L

         float - 4字节,直接赋值时必须在数字后加上 f 或 F
         double - 8字节,赋值时一般在数字后加 d 或 D

        char - 2字节,存储 Unicode 码,用单引号赋值

         boolean - 1字节,只有 true 和 false 两个取值,一个字节就够了

2、所有的非基本数据类型都是引用数据类型,除了基本数据类型对应的引用类型外,类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型都属于引用类型。

主要有以下区别:

有了基础知识的补充之后,我们通过两个例子来学习String的intern方法

使用 intern 方法,主动将串池中还没有的字符串对象放入串池

例一、 

        String s1 = new String("a")+new String("b");
        String s2=s1.intern();
        System.out.println(s2=="ab");
        System.out.println(s1=="ab");

 

第一行代码:

因为"a","b"是常量,被依次放入串池中,此时串池中有["a","b"]

new String("a")  new String("b") 是新的对象,放进堆中,值和串池中的相等,但是对象不是同一个。

s1是通过StringBuilder拼接了"a"和"b",形成一个新对象  new String("ab"),也放入堆中,并没有放入串池中,因为"ab"是动态拼接成的,串池中是放常量字符串。

此时堆中有 [new String("a")  new String("b")  new String("ab")]

     串池中有["a","b"]

第二行代码:

如果想将"ab"放入串池中,可以调用String的intern()方法,将s1这个字符串对象尝试放入串池,如果有则不会放入,如果没有则将s1放入串池,并把串池中的对象返回。

所以此时串池中有["a","b","ab"],s2引用的对象是串池中的对象

第三行代码:

执行第三行代码时,会在串池中先看看有没有"ab",结果发现有了,就不会再在串池中引用新的对象了,此时==后的"ab"就是串池中的"ab",因此第三行代码结果返回true

第四行代码:

执行第二行代码时已经把s1对象放入了串池,所以第四行代码返回true

程序执行结果如图:

 

例二

        String s="ab";
        String s1 = new String("a")+new String("b");
        String s2=s1.intern();
        System.out.println(s2==s);
        System.out.println(s1==s);

第一行代码:

执行第一行代码前,串池是空的,因此在串池中放入常量"ab" 

第二行代码:

同例一,在串池中依次放入"a","b",new String("a")  new String("b")  new String("ab")依次放入堆中

此时串池中有["ab","a,"b"],注意:此时堆中的 new String("ab")和串池中的"ab"不是一个对象

第三行代码:

执行intern方法,但是此时串池中已经有"ab",所以s1对象不会放入串池中,而返回的s2是串池中对象,所以执行第四行代码时,返回的结果是true,而第五行代码返回的是false

程序结果如图所示:

总结

String的intern方法,会将这个字符对象尝试放入串池中,如果串池中已经有这个常量,就不将这个对象放入池中,如果没有就将这个对象放入池中,,并且返回的是串池中的对象,也就是说intern方法返回的对象和调用方法的对象不一定是同一个对象,但是值是相同的。

字符串变量拼接的原理是StringBuilder

字符串常量拼接的原理是编译器优化

 附录

另外还有一道面试题

String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();
// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢
System.out.println(x1 == x2);

我们不运行程序来看一下执行结果:

前三行代码执行完之后,串池中有["a","b","ab"]

s4,s1+s2实际上是通过StringBuilder方法拼接成"ab",放入堆中

s5的"ab"在串池中已经存在,因此不放入串池中,但是和s3是同一个对象

s6行代码执行了intern方法,因为串池中已经有"ab"对象了,所以s4并不放入串池中,凡是返回的是串池中的"ab",因此s6和s3是同一个对象

综上,s3==s4结果为false

s3==s5结果为true

s3==s6结果为true

同理 x1==x2返回false,如果两行代码调换顺序,结果为true

如果是jdk1.6,无论代码换不换,结果都为false,因为在1.6中的intern方法返回的对象和调用方法的对象不是同一个

                            

标签:ab,String,对象,intern,详解,串池,new,放入
来源: https://blog.csdn.net/m0_59181747/article/details/121146280