Java中Class类对象详解

Class类简介:

  在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。

  每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。

  Java使用Class对象执行其RTTI(运行时类型识别,Run-Time Type Identification),多态是基于RTTI实现的。

  每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型 (boolean, byte, char, short, int, long, float, and double)有Class对象,数组有Class对象,就连关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对的抽象和集合。

  Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。一个类被加载到内存并供我们使用需要经历如下三个阶段:

  1. 加载,这是由类加载器(ClassLoader)执行的。通过一个类的全限定名来获取其定义的二进制字节流(Class字节码),将这个字节流所代表的静态存储结构转化为方法去的运行时数据接口,根据字节码在java堆中生成一个代表这个类的java.lang.Class对象。

  2. 链接。在链接阶段将验证Class文件中的字节流包含的信息是否符合当前虚拟机的要求,为静态域分配存储空间并设置类变量的初始值(默认的零值),并且如果必需的话,将常量池中的符号引用转化为直接引用。

  3. 初始化。到了此阶段,才真正开始执行类中定义的java程序代码。用于执行该类的静态初始器和静态初始块,如果该类有父类的话,则优先对其父类进行初始化。

  所有的类都是在对其第一次使用时,动态加载到JVM中的(懒加载)。当程序创建第一个对类的静态成员的引用时,就会加载这个类。使用new创建类对象的时候也会被当作对类的静态成员的引用。因此java程序程序在它开始运行之前并非被完全加载,其各个类都是在必需时才加载的。这一点与许多传统语言都不同。动态加载使能的行为,在诸如C++这样的静态加载语言中是很难或者根本不可能复制的。

  在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良java代码。一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象。

Dog.class、dog.getClass、Class.forName区别:

 1 class Dog {
 2 
 3     //存放在静态常量池
 4     static final String name = "Tom";
 5     static String sex = "Tom is man";
 6 
 7     //初始化是在类加载时进行的。
 8     static {
 9         System.out.println("Loading Tom");
10     }
11 }
12 
13 class Cat {
14 
15     //放在静态常量池
16     static final String name = "Mark";
17     static String sex = "Mark is man";
18 
19     //初始化是在类加载时进行的。
20     static {
21         System.out.println("Loading Mark");
22     }
23 }
24 
25 public class ClassInfo {
26 
27     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
28         System.out.println("-start dog-");
29         Class dog = Dog.class;  //JVM将使用类Dog的类装载器,将类Dog装入内存(前提是:类Dog还没有装入内存),不对类Dog做类的初始化工作.返回类Dog的Class的对象。
30         System.out.println("-----------");
31         System.out.println(Dog.name);
32         System.out.println("-----------");
33         System.out.println(Dog.sex); //通过反编译得出,此时初始化Dog对象。
34         System.out.println("-start Cat-");
35         Class cat = Class.forName("Cat"); //装入Cat类,并做类的初始化。
36         System.out.println("-----------");
37         System.out.println(Cat.name);
38         System.out.println("-----------");
39         System.out.println(Cat.sex);
40 
41         Dog daHuang = new Dog();
42         Class daHuangClass = daHuang.getClass(); //返回引用daHuangClass运行时真正所指的对象(因为:儿子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象。
43 
44         Class<Cat> xiaoBai = Cat.class;  //得到class对象
45         Cat instance = xiaoBai.newInstance();//返回cat对象
46         // 使用Class对象的newInstance()方法的时候,就必须保证:1、这个 类已经加载;2、这个类已经连接了。
47         // 而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。
48 
49         // new关键字和newInstance()方法的区别:
50         // newInstance: 弱类型。低效率。只能调用无参构造。
51         // new: 强类型。相对高效。能调用任何public构造。
52     }
53 
54 }

推荐阅读:https://blog.csdn.net/forrestgtju/article/details/92594144

     https://blog.csdn.net/Activity_Time/article/details/96865451

     https://blog.csdn.net/hanleijun/article/details/24576539

猜你喜欢

转载自www.cnblogs.com/mxh-java/p/11918888.html