一.Java语言是先把Java源文件编译成后缀为class的字节码文件,而后再经过ClassLoader机制把这些类文件加载到内存中,最后生成实例执行的,这是Java处理的基本机制,可是加载到内存中的数据的如何描述一个类的呢?好比在Dog.class文件中定义一个Dog类,那它在内存中是如何展示的呢?java
Java使用一个元类(MetaClass)来描述加载到内存中的类数据,这就是Class类,它是一个描述类的类对象,好比Dog.class文件加载到内存中后就会有一个class的实例对象描述之。由于是Class类是“类中类”,也就有预示着它有不少特殊的地方:编程
1. 无构造函数:Java中的类通常都有构造函数,用于建立实例对象,可是Class类却没有公共的构造方法,不能实例化,Class对象是在加载类时由Java虚拟机经过调用类加载器中的difineClass方法自动构造的,所以不能显示的声明一个class对象。框架
2. 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象,虽然8个基本类型在JVM中并非一个对象,它们通常存在于栈内存中,可是Class类仍然能够描述它们,例如可使用int.class表示int类型的类对象。函数
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每一个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。若是没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。其对象都是单例模式:一个Class的实例对象描述一个类,而且只描述一个类,反过来也成立。一个类只有一个Class实例对象,以下代码返回的结果都为true: 对象
下面咱们用java来看一看java语言自己是怎么描述这个问题的。内存
public class Test {字符串
public static void main(String[] args) {get
People xiaoming = new People();原型
System.out.println(xiaoming.getClass());//小明这个对象为People类的一个对象虚拟机
System.out.println(xiaoming.getClass().getClass());//People这个对象为Class元类的一个对象
System.out.println(xiaoming.getClass().getClass().getClass());//Class这个对象为Class元类的一个对象
}
}
class pyf.java.test.People
class java.lang.Class
class java.lang.Class
二.怎么获取类的元类型
那么java中怎么获取一个类的元类呢?大概有下面这么几种方法:
1)类型.class (类属性方式)
这种方式很直接,引用类型可使用该方式来获取元类,基本类型也能经过该方式获取元类
Class c1 = int.class;
Class c2 = InputStream.class;
2)实例.getClass()
这种方式是经过一个实例调用基类Object的方法
Person xiaoming = new Person();
Class<Person> cls = xiaoming.getClass();
Object的getClass方法原型以下:
public final native Class<?> getClass();
3)Class.forName(className)
这种方式,className指的是采用类的彻底限定名(完整的包名+类名,若是是内部类,则是包名+类名$内部类名),使用这种方式很灵活,由于参数是字符串,能够结合配置文件来达到动态效果。
//假设类在pyf.java.demo包下,类名为Person,则获取方法以下
Class<?> cls = Class.forName("pyf.java.demo.Person");
Class.forName方式对于玩过jdbc的小伙伴应该很熟悉了,在加载jdbc驱动时就使用了该种方式
//DRIVER为配置的jdbc驱动名称
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
使用场景
获取元类的场景通常是在用到反射时,由于经过元类能拿到类自己的信息,如类的成员变量,构造方法,方法等,这为动态化编程带来了方便,这也是不少框架的基础。得到了Class对象后,就能够经过getAnnotations()得到注解,经过getMethods()得到方法,经过getConstructors()得到构造函数等,后续的反射代码铺平了道路。
3、总结:
1.万物皆对象 2.抽象是具体的抽象,具体是抽象的具体 3.实例,类,元类的关系:具体,抽象,再抽象 4.元类的三种获取方式 类型.class,实例.getClass,Class.forName(“类彻底限定名”)