[jvm]深入JVM(一):从"abc"=="abc"看java的连接过程

来源:互联网 发布:java snmp4j jar 编辑:程序博客网 时间:2024/06/05 20:35

一般说来,我不关注java底层的东西,这次是一个朋友问到了,注意不光是  System.out.println("abc"=="abc");返回true, System.out.println(("a"+"b"+"c").intern()=="abc");也返回true;这和java的连接过程有关。
java解析CONSTANT_String_info时,java虚拟机必须把一个字符串对象的引用,放到constant pool entry 中。每个java虚拟机维护着一张列表,里面有所有程序被"interned"的字符串对象的引用。
查看constPoolOop.cpp文件
oop constantPoolOopDesc::string_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
  oop entry = *(this_oop->obj_at_addr(which));
  if (entry->is_symbol()) {
    ObjectLocker ol(this_oop, THREAD);
    if (this_oop->tag_at(which).is_unresolved_string()) {
      // Intern string
      symbolOop sym = this_oop->unresolved_string_at(which);
      entry = StringTable::intern(sym, CHECK_(constantPoolOop(NULL)));
      this_oop->string_at_put(which, entry);
    } else {
      // Another thread beat us and interned string, read string from constant pool
      entry = this_oop->resolved_string_at(which);
    }
  }
  assert(java_lang_String::is_instance(entry), "must be string");
  return entry;
}
注意有特定字符序列的字符串只会出现一次。如果存在这个Unicode字符序列的字符串,直接返回这个字符串的引用,否则创建新的字符串对象。
查看symbolTable.cpp文件
oop StringTable::intern(Handle string_or_null, jchar* name,
                        int len, TRAPS) {
  unsigned int hashValue = hash_string(name, len);
  int index = the_table()->hash_to_index(hashValue);
  oop string = the_table()->lookup(index, name, len, hashValue);

  // Found
  if (string != NULL) return string;
 
  // Otherwise, add to symbol to table
  return the_table()->basic_add(index, string_or_null, name, len,
                                hashValue, CHECK_0); 
}
the_table()的定义,SymbolTable* SymbolTable::_the_table = NULL;
使用string类的intern()方法,来intern一个字符串,如果具有相同字符序列的字符串被intern过,那末intern()方法直接返回被interned字符串对象的引用。
这样的代码
  public static final String a="123";
    public static final String b="123";
 System.out.println(a==b);

返回也是true,如果一个程序多个类使用相同的字符串,这些类的方法使用ldc或者ldc_w把内容为"123"的string对象的引用压入栈。也就是说java虚拟机把所有具有相同字符顺序的字符串处理为同一个java对象。
对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
从String源码得知这是一个native方法。
查看jdk代码
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))
  JVMWrapper("JVM_InternString");
  JvmtiVMObjectAllocEventCollector oam;
  if (str == NULL) return NULL;
  oop string = JNIHandles::resolve_non_null(str);
  oop result = StringTable::intern(string, CHECK_0);
  return (jstring) JNIHandles::make_local(env, result);
JVM_END
也调用了StringTable::intern。