/**
* Created by root on 20-12-26.
*/
public class Foo {
public static void main(String[] args) throws InterruptedException {
String s1 = new StringBuilder("go").append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja").append("va").toString();
System.out.println(s2.intern() == s2);
String s3 = new StringBuilder("java.").append("version").toString();
System.out.println(s3.intern() == s3);
String s4 = new StringBuilder("open").append("jdk").toString();
System.out.println(s4.intern() == s4);
}
}
输出的结果:
true
false
false
true
为什么同样操作结果却不一样?
答案是:在jvm运行到这个main方法之前加载过java和java.version这两个字符串了。
那么问题来了,何时加载?以什么方式加载的呢?
PS : 知乎上R大在2016年已经有完整的解释了,链接在下方。
答案
是jvm在创建的时候,调用java的rt.jar包下面,
java.lang.System类中,initializeSystemClass静态方法。
这个方法会调用sun.misc.Version.init()方法,然而Version.class的结构是这样的,如下图:
继续深究
我手边正好有jdk-8(jvm)的debug环境,就debug了一下,想找出在哪里调用的。出乎我的意料的是,跑出来的答案完全不一样,如下图:
结果是:
java为true,openjdk为false,为什么呢?
我想坑定是sun.misc.Version这个类有啥问题,我立马打开
我的类,发现了端倪,如下图:
好吧,我的launcher_name竟然是openjdk。原来如此!!!
最后的问题
何时调用?以什么方式调用的呢?直接上图吧,如下:
JavaCalls::call_static 这个方法是hotspot虚拟机调用jdk的惯用伎俩。
接着调用你的mainClass了,如下图:
具体为啥要调用,这些东西,以后在研究吧,我要睡觉了。
R大还是牛逼啊,哈哈!
(R大)链接:https://www.zhihu.com/question/51102308
PS:祝大家圣诞 元旦快乐!