Java中,这些字符串什么时候进入常量池的?

只考虑JDK1.8String s1 = new StringBuilder("tr").append("ue").toString(); System.out.println(s1.intern() == s1);这段代码结果为false,说明"true"这个字符串已经在常量池中了,类似的还有int、float、java...,为什么?
关注者
37
被浏览
5464
又见好奇宝宝…哈哈这个好办。

题主的问题里,"java"是何时被intern的我已经在之前的一个回答里详细讲解了:
如何理解《深入理解java虚拟机》第二版中对String.intern()方法的讲解中所举的例子? - RednaxelaFX 的回答 - 知乎

下面我们就按上面的传送门来按图索骥,照猫画虎,找出"true"和"int"分别是在哪里被intern的。

我这边的实验环境随手用了个Mac上的Oracle JDK7u45。但换用Oracle JDK8的结果也是基本一样的,因为这俩版本的JDK里的HotSpot VM对String interning的实现基本上是一样的,而且JDK标准库一侧在初始化过程中对字面量的使用变化也不太大。感兴趣的同学可以自己跑跑看。

"true"
(lldb) bt
* thread #4: tid = 0x205cfd1, 0x00000001024bc2da libjvm.dylib`StringTable::lookup(int, unsigned short*, int, unsigned int), stop reason = breakpoint 1.1
  * frame #0: 0x00000001024bc2da libjvm.dylib`StringTable::lookup(int, unsigned short*, int, unsigned int)
    frame #1: 0x00000001024bc539 libjvm.dylib`StringTable::intern(Handle, unsigned short*, int, Thread*) + 79
    frame #2: 0x00000001024bc75c libjvm.dylib`StringTable::intern(Symbol*, Thread*) + 90
    frame #3: 0x00000001021e7b7f libjvm.dylib`constantPoolOopDesc::string_at_impl(constantPoolHandle, int, Thread*) + 111
    frame #4: 0x00000001022d329a libjvm.dylib`InterpreterRuntime::ldc(JavaThread*, bool) + 158
    frame #5: 0x0000000104013fe0 sun.misc.VM.saveAndRemoveProperties(VM.java:283)
    frame #6: 0x0000000104006058 java.lang.System.initializeSystemClass(System.java:1135)
    frame #7: 0x00000001040004e7 call_stub
    frame #8: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #9: 0x00000001022d6ec1 libjvm.dylib`JavaCalls::call_static(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) + 145
    frame #10: 0x00000001022d6fc3 libjvm.dylib`JavaCalls::call_static(JavaValue*, KlassHandle, Symbol*, Symbol*, Thread*) + 57
    frame #11: 0x00000001024f260c libjvm.dylib`Threads::create_vm(JavaVMInitArgs*, bool*) + 2740
    frame #12: 0x0000000102309be1 libjvm.dylib`JNI_CreateJavaVM + 98
    frame #13: 0x0000000100002915 java`JavaMain + 308
    frame #14: 0x00007fff8d7ce899 libsystem_pthread.dylib`_pthread_body + 138
    frame #15: 0x00007fff8d7ce72a libsystem_pthread.dylib`_pthread_start + 137
    frame #16: 0x00007fff8d7d2fc9 libsystem_pthread.dylib`thread_start + 13
我们来看看Oracle JDK7u45的 sun.misc.VM. saveAndRemoveProperties() 里面都做了些什么事情?
hg.openjdk.java.net/jdk
    public static void saveAndRemoveProperties(Properties props) {
        //...

        // Check if direct buffers should be page aligned
        s = (String)props.remove("sun.nio.PageAlignDirectMemory");
        if ("true".equals(s))
            pageAlignDirectMemory = true;

        // ...
}
看到那个可爱的"true"字面量了不?

"false" - 在Oracle JDK7u45中,JDK标准库的类在进入用户指定的主类的main()之前并不会intern这个字符串。

"int"
(lldb) bt
* thread #4: tid = 0x206e278, 0x00000001024bc2da libjvm.dylib`StringTable::lookup(int, unsigned short*, int, unsigned int), stop reason = breakpoint 1.1
  * frame #0: 0x00000001024bc2da libjvm.dylib`StringTable::lookup(int, unsigned short*, int, unsigned int)
    frame #1: 0x00000001024bc539 libjvm.dylib`StringTable::intern(Handle, unsigned short*, int, Thread*) + 79
    frame #2: 0x00000001024bc75c libjvm.dylib`StringTable::intern(Symbol*, Thread*) + 90
    frame #3: 0x00000001021e7b7f libjvm.dylib`constantPoolOopDesc::string_at_impl(constantPoolHandle, int, Thread*) + 111
    frame #4: 0x00000001022d329a libjvm.dylib`InterpreterRuntime::ldc(JavaThread*, bool) + 158
    frame #5: 0x0000000104013fe0 java.lang.Integer.<clinit>(Integer.java:71)
    frame #6: 0x00000001040004e7 call_stub
    frame #7: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #8: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #9: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #10: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #11: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #12: 0x000000010239f5ab libjvm.dylib`LinkResolver::resolve_static_call(CallInfo&, KlassHandle&, Symbol*, Symbol*, KlassHandle, bool, bool, Thread*) + 173
    frame #13: 0x000000010239f691 libjvm.dylib`LinkResolver::resolve_invokestatic(CallInfo&, constantPoolHandle, int, Thread*) + 129
    frame #14: 0x00000001022d1f22 libjvm.dylib`InterpreterRuntime::resolve_invoke(JavaThread*, Bytecodes::Code) + 550
    frame #15: 0x000000010401d788 java.util.HashMap.roundUpToPowerOf2(HashMap.java:303)
    frame #16: 0x00000001040061d4 java.util.HashMap.inflateTable(HashMap.java:317)
    frame #17: 0x0000000104006058 java.util.HashMap.put(HashMap.java:492)
    frame #18: 0x00000001040068e1 sun.reflect.Reflection.<clinit>(Reflection.java:47)
    frame #19: 0x00000001040004e7 call_stub
    frame #20: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #21: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #22: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #23: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #24: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #25: 0x000000010239f5ab libjvm.dylib`LinkResolver::resolve_static_call(CallInfo&, KlassHandle&, Symbol*, Symbol*, KlassHandle, bool, bool, Thread*) + 173
    frame #26: 0x000000010239f691 libjvm.dylib`LinkResolver::resolve_invokestatic(CallInfo&, constantPoolHandle, int, Thread*) + 129
    frame #27: 0x00000001022d1f22 libjvm.dylib`InterpreterRuntime::resolve_invoke(JavaThread*, Bytecodes::Code) + 550
    frame #28: 0x000000010401d77a sun.misc.Unsafe.<clinit>(Unsafe.java:49)
    frame #29: 0x00000001040004e7 call_stub
    frame #30: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #31: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #32: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #33: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #34: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #35: 0x000000010239f5ab libjvm.dylib`LinkResolver::resolve_static_call(CallInfo&, KlassHandle&, Symbol*, Symbol*, KlassHandle, bool, bool, Thread*) + 173
    frame #36: 0x000000010239f691 libjvm.dylib`LinkResolver::resolve_invokestatic(CallInfo&, constantPoolHandle, int, Thread*) + 129
    frame #37: 0x00000001022d1f22 libjvm.dylib`InterpreterRuntime::resolve_invoke(JavaThread*, Bytecodes::Code) + 550
    frame #38: 0x000000010401d788 java.util.concurrent.atomic.AtomicInteger.<clinit>(AtomicInteger.java:56)
    frame #39: 0x00000001040004e7 call_stub
    frame #40: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #41: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #42: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #43: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #44: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #45: 0x00000001022d2fad libjvm.dylib`InterpreterRuntime::_new(JavaThread*, constantPoolOopDesc*, int) + 161
    frame #46: 0x000000010401e0f7 java.lang.ThreadLocal.<clinit>(ThreadLocal.java:89)
    frame #47: 0x00000001040004e7 call_stub
    frame #48: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #49: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #50: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #51: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #52: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #53: 0x00000001022d2fad libjvm.dylib`InterpreterRuntime::_new(JavaThread*, constantPoolOopDesc*, int) + 161
    frame #54: 0x000000010401e0f7 java.nio.charset.Charset.<clinit>(Charset.java:389)
    frame #55: 0x00000001040004e7 call_stub
    frame #56: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #57: 0x00000001022d6b60 libjvm.dylib`JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
    frame #58: 0x00000001022ac367 libjvm.dylib`instanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*) + 147
    frame #59: 0x00000001022ad856 libjvm.dylib`instanceKlass::initialize_impl(instanceKlassHandle, Thread*) + 1484
    frame #60: 0x000000010229fd01 libjvm.dylib`instanceKlass::initialize(Thread*) + 85
    frame #61: 0x0000000102323810 libjvm.dylib`find_class_from_class_loader(JNIEnv_*, Symbol*, unsigned char, Handle, Handle, unsigned char, Thread*) + 120
    frame #62: 0x00000001022fa6bb libjvm.dylib`jni_FindClass + 641
    frame #63: 0x000000010032bc7f libjava.dylib`JNU_CallStaticMethodByName + 154
    frame #64: 0x000000010032bf0c libjava.dylib`jnuEncodingSupported + 56
    frame #65: 0x000000010032ca7e libjava.dylib`JNU_NewStringPlatform + 550
    frame #66: 0x00000001003291f5 libjava.dylib`Java_java_lang_System_initProperties + 7090
    frame #67: 0x0000000104012698 java.lang.System.initProperties(Native Method)
    frame #68: 0x0000000104006233 java.lang.System.initializeSystemClass(System.java:1119)
    frame #69: 0x00000001040004e7 call_stub
    frame #70: 0x00000001022d6d90 libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 554
    frame #71: 0x00000001022d6ec1 libjvm.dylib`JavaCalls::call_static(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) + 145
    frame #72: 0x00000001022d6fc3 libjvm.dylib`JavaCalls::call_static(JavaValue*, KlassHandle, Symbol*, Symbol*, Thread*) + 57
    frame #73: 0x00000001024f260c libjvm.dylib`Threads::create_vm(JavaVMInitArgs*, bool*) + 2740
    frame #74: 0x0000000102309be1 libjvm.dylib`JNI_CreateJavaVM + 98
    frame #75: 0x0000000100002915 java`JavaMain + 308
    frame #76: 0x00007fff8d7ce899 libsystem_pthread.dylib`_pthread_body + 138
    frame #77: 0x00007fff8d7ce72a libsystem_pthread.dylib`_pthread_start + 137
    frame #78: 0x00007fff8d7d2fc9 libsystem_pthread.dylib`thread_start + 13
所以在Oracle JDK7u45上,"int"是由java.lang.Integer的类初始化器所intern的。
hg.openjdk.java.net/jdk
    public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
这 Integer.TYPE 是个有趣的东西。请跳传送门:谁来解释下基本类型变量的class,如int.class.什么时候会使用它们? - RednaxelaFX 的回答 - 知乎

其它例子就作为习题留给感兴趣好奇宝宝啦 >_<