当前位置: 首页 > 最新文章 > 正文

初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

如果将jdk换成1.6输出结果是?用于分解class文件。加载完成后这些常量还并不是java字符串对象,当程序执行 String s1 = "a"这行代码时,就会把s1变成字符串"a"的对象。同时会准备一块空间,也就是串池。初始化串池后就会把字符串"a"当做key,去串池中查找是否已经存在,如果不存在就会把字符串"a"放入串池,如果存在就不放入。这种就是javac在编译期的优化策略,虚拟机认为"a

admin

如果将jdk换成1.6输出结果是?用于分解class文件。加载完成后这些常量还并不是java字符串对象,当程序执行 String s1 = "a"这行代码时,就会把s1变成字符串"a"的对象。同时会准备一块空间,也就是串池。初始化串池后就会把字符串"a"当做key,去串池中查找是否已经存在,如果不存在就会把字符串"a"放入串池,如果存在就不放入。这种就是javac在编译期的优化策略,虚拟机认为"a"和"b"都是常量,不会再发生变化,在编译期间就可以确认结果就是"ab"。看到这里是不是完全明白了关于String对象的各种面试问题了,赶紧尝试着再去回答一下开始的问题吧!

首先伙伴们回答一下关于Java String类在面试中经常遇到的问题,如果你能完全回答正确并且明白其实现逻辑,接下来的内容你可以忽略,跟你已经没有关系了。

public class StringTest {    public static void main(String[] args) {        //运行环境jdk1.8        String s1 = "a";        String s2 = "b";        String s3 = s1+s2;        String s4 = "a"+"b";        String s5 = "ab";        String s6 = s3.intern();        //问:        System.out.println(s3 == s4);        System.out.println(s5 == s4);        System.out.println(s6 == s4);        String str1 = new String("s")+new String("tr");        String str2 = "str";        str1.intern();        //问:如果25、26行代码交换位置输出结果是?如果将jdk换成1.6输出结果是?        System.out.println(str1 == str2);    }}//请说出你的答案,评论区里见
初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

开始分析问题

解释字符串常量和串池的关系

String s1 = "a";//思考:程序运行到这行代码时实现了什么逻辑?

通过javap -v my.class命令反解析class文件,我们会看到下图1的两行指令,其中,ldc #2是代表要去常量池的2号位置加载信息,此信息可以是一个常量也可以是一个对象的引用;astore_1是把加载好的信息存入到1号局部变量,如图2:

初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

图1

初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

图2

提示:javap是 Java class文件分解器,可以反编译(即对javac编译的文件进行反编译),也可以查看java编译器生成的字节码。用于分解class文件。

当程序运行的时候,会把字符串常量加载到运行时常量池,见图3 。加载完成后这些常量还并不是java字符串对象,当程序执行 String s1 = "a"这行代码时,就会把s1变成字符串"a"的对象。同时会准备一块空间,也就是串池(stringTable)。初始化串池后就会把字符串"a"当做key,去串池中查找是否已经存在,如果不存在就会把字符串"a"放入串池,如果存在就不放入。

初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

图3

字符串变量拼接时jvm如何工作的?

String s3 = s1+s2;//思考:执行这行代码时触发了哪些操作?

直接看图4反编译后的代码,我们会发现,按照图中执行的命令转换成Java代码其实就是下面的代码片段:StringBuilder b = new StringBuilder();b.append("a").append("b").toString();

初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

图4

//    StringBuilder 类的toString()方法public String toString() {        return new String(this.value, 0, this.count);    }

总结:字符串变量拼接其原理就是调用了StringBuilder的append()方法,然后再调用StringBuilder的toString() 方法,StringBuilder的toString()方法底层实现是new String对象。

System.out.println(s3 == s5);//看到这里就应该知道结果了吧,是的没错就是:false //原因就是s3在已经在串池中而s5是在堆中。

Jvm编译期优化

String s4 = "a"+"b";//此行代码在编译器会是如何执行的呢?
初级程序员必懂jdk1.6和1.8版本中关于String类面试官关心的问题

在反编译的代码中可以看到"a"+"b"执行后对应的是"ab",与String s5 = "ab";直接赋值后的指令完全一样,而且都是去常量池#8位置找同一个值。 这种就是javac在编译期的优化策略,虚拟机认为"a"和"b"都是常量,不会再发生变化,在编译期间就可以确认结果就是"ab"。

System.out.println(s5 == s4);//这个执行结果就是:true

使用intern()主动将串池中没有的字符串放入串池

String str1 = new String("s")+new String("tr");//jdk1.8环境下 str1.intern();

把上面这行代码拆分可以获得:字符串"s"和"tr"会添加到串池,new String("s")和new String("tr")会存入堆中,str1的执行结果:"+"在上面已经解释过了其实就是Stringbuilder.append().toString(),最终得到一个存在堆中的String对象。

jdk1.8的str1.intern();尝试将字符串对象放入串池中,如果串池中没有就会放入,如果串池中存在则不会放入,并且会返回串池中的对象。

jdk1.6的str1.intern();尝试将字符串对象放入串池中,如果串池中没有就会复制一份此对象,并把复制后的对象放入串池中,如果串池中存在则不会放入,并且会返回串池中的对象。

看到这里是不是完全明白了关于String对象的各种面试问题了,赶紧尝试着再去回答一下开始的问题吧!


上一篇: 电脑坏了修好后会影响电脑的性能吗?别傻傻地被蒙在鼓里了 下一篇:超全PPT矢量图标素材.pptx在线浏览共计232页大小23M左右值得收藏
返回顶部