java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java的klass和class

关于Java中的klass和class

作者:云川之下

这篇文章主要介绍了关于Java中klass和class的区别,vm加载的字节码,也就是.class文件,被加载到方法区里面,叫Kclass,是一个C++对象,含有类的信息、虚方法表等,需要的朋友可以参考下

Java的klass和class

vm加载的字节码,也就是.class文件,被加载到方法区里面,叫Kclass,是一个C++对象,含有类的信息、虚方法表等

下文中说的mirror是指,JVM在加载了字节码后,在堆里创建的Class对象,这个对象和方法区的Kclass相互指向,也就是说我们可以通过Kclass找到这个对象

我们new 一个对象,对象头里面会有一个指针,指向方法区的Kclass

new Object().getClass()流程, 对象头里面的指针–>方法区kClass–>堆Class对象

反射也是拿到堆里的Class对象

所有我们比较两个对象类型是否相等,实际上就是比较两个Class对象是否一样

本节课,我们深入地理解一下反射中使用的Class类,Method类,Field类这三个类。

其中,重点中的重点是Class类和Class对象。这个概念太容易混淆。

我在写这篇文章之前,先在网上搜了一下,发现没有一篇文章是能讲得很清楚的。

确实很少有文章能讲明白

知乎上有很多大牛,关于Class对象也曾留下过只言片语,但又不够系统,因为对于这些进行JVM开发的牛人而言,Class对象是一个不屑于说的问题。但就是在这样的,开发者有点糊涂,大牛觉得不重要的地方,才容易产生知识的死角。而且网上有很多错误的概念,以讹传讹,更加容易让新手们搞不清楚。

先给结论,每一个Java类都有一个伴生的Class对象。

详细解释一下,定义这样一个类:

class Main {
}

那么当这个类所在的文件被加载,更准确地说,这个类被ClassLoader加载到JVM中的时候,Hotspot虚拟机会为这个类在虚拟机内部创建一个叫做Klass的数据结构:

class Klass : public Metadata {
  friend class VMStructs;
 protected:
  // note: put frequently-used fields together at start of klass structure
  // for better cache behavior (may not make much of a difference but sure won't hurt)
  enum { _primary_super_limit = 8 };
  jint        _layout_helper;
  juint       _super_check_offset;
  Symbol*     _name;
  Klass*      _secondary_super_cache;
  // Array of all secondary supertypes
  Array<Klass*>* _secondary_supers;
  // Ordered list of all primary supertypes
  Klass*      _primary_supers[_primary_super_limit];
  // java/lang/Class instance mirroring this class
  oop       _java_mirror;
  // Superclass
  Klass*      _super;
  // First subclass (NULL if none); _subklass->next_sibling() is next one
  Klass*      _subklass;
  // Sibling link (or NULL); links all subklasses of a klass
  Klass*      _next_sibling;
  Klass*      _next_link;
  // The VM's representation of the ClassLoader used to load this class.
  // Provide access the corresponding instance java.lang.ClassLoader.
  ClassLoaderData* _class_loader_data;
  jint        _modifier_flags;  // Processed access flags, for use by Class.getModifiers.
  AccessFlags _access_flags;    // Access flags. The class/interface distinction is stored here.
  // Biased locking implementation and statistics
  // (the 64-bit chunk goes first, to avoid some fragmentation)
  jlong    _last_biased_lock_bulk_revocation_time;
  markOop  _prototype_header;   // Used when biased locking is both enabled and disabled for this type
  jint     _biased_lock_revocation_count;
  TRACE_DEFINE_KLASS_TRACE_ID;
  // Remembered sets support for the oops in the klasses.
  jbyte _modified_oops;             // Card Table Equivalent (YC/CMS support)
  jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
....
}

这个类的完整定义,大家可以去看hotspot/src/share/vm/oops/klass.hpp, 我们这里就不再多列了。这些属性已经足够我们讲解的了。

如果Main class被加载,那么虚拟机内部就会为它创建一个 Klass ,它的 _name 属性就是字符串 “Main”。

_primary_supers 代表了这个类的父类。比如,我们看IOException, 是Exception的子类,而Exception又是Throwable的子类。

那么,如果你去看IOException的 _primary_supers 属性就会发现,它是这样的:[Throwable, Exception, IOException],后面5位为空。

其他的属性我们先不看,以后有时间会慢慢再来讲。

今天重点说一下oop,这个我猜是ordinary object pointer的缩写,到底是什么的缩写,其实我也不确定。

但我能确定的是,这种类型代表是一个真正的Java对象。比如说:

Main m = new Main();

这行语句里创建的 m 在JVM中,就是一个oop,是一个普通的Java对象,而Main在JVM里则是一个Klass。

大家理清了这里面的关系了吗?我建议没看懂的,再多看一遍。一般地来说,我不是很鼓励新手学习JVM源代码。但是有一些核心概念,如果能加以掌握的话,还是有利于快速掌握概念的本质的。

好了。说了这么多,才刚来到我们今天的主题: java_mirror 。不起眼的一行:

 // java/lang/Class instance mirroring this class
  oop       _java_mirror;

注释说得很清楚了,这个属性代表的就是本class的Class对象。举例来说,如果JVM加载了Main这个类,那么除了为Main创建了一个名为"Main"的Klass,还默默地背后创建一个object,并且把这个object 挂到了 Klass 的 _java_mirror 属性上了。

那我们通过Java代码能不能访问到这个背后的对象呢?你肯定已经猜到了,当然能啊,这就是Main的class对象啊。我们上节课已经有两种写法来访问它了啊:

Class m = Main.class;
Class m = Class.forName("Main");

这两种方法都能访问到Main的Class object,也就是 Klass 上那个不起眼的 _java_mirror 。那么这个_java_mirror上定义的 newInstance 方法,其实最终也是通过JVM中的方法来创建真正的对象:

JVM_ENTRY(jobject, JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0))
  JVMWrapper("JVM_NewInstanceFromConstructor");
  oop constructor_mirror = JNIHandles::resolve(c);
  objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
  oop result = Reflection::invoke_constructor(constructor_mirror, args, CHECK_NULL);
  jobject res = JNIHandles::make_local(env, result);
  if (JvmtiExport::should_post_vm_object_alloc()) {
    JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
  }
  return res; 
JVM_END

这个函数到这里我们就不再往下追了,只要知道JVM可以通过 java_mirror 找到真正的 Klass ,然后再用这个 Klass 创建一个真正的对象就可以了。

到此这篇关于关于Java中的klass和class的文章就介绍到这了,更多相关Java的klass和class内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文