Class对象
虚拟机在class文件的加载阶段,把类信息保存在方法区数据结构中,并在Java堆中生成一个Class对象,作为类信息的入口。
获取Class对象一般有三种方式:
-
通过实例变量方式
代码块
Check check = new Check(); Class<? extends Check> clazz = check.getClass();
-
通过类名方式
过这种方式时,只会加载Dog类,并不会触发其类构造器的初始化。
代码块
Class<Check> checkClass = Check.class;
-
通过Class.forName(String classname)方式
代码块
Class<?> check1 = Class.forName("Check");
在JDK源码实现中,forName方法会调用Native方法forName0(),它在JVM中调用findClassFromClassLoader()加载Dog类,其原理和ClassLoader一样,将会触发Dog类的类构造器初始化,forName0方法声明如下:
代码块
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
其中initialize参数,用来告诉虚拟机是否需要对加载的类进行初始化,如果initialize为false,则不会进行初始化Dog类。
反射机制
反射机制reflect可以在运行期间获取类的字段、方法、父类和接口等信息。
1、获取类字段
代码块
Class class_dog = Check.class;
Field[] fields = class_dog.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
2、获取类方法
代码块
Class class_dog = Check.class;
Method[] declaredMethods = class_dog.getDeclaredMethods();
for (Method field : declaredMethods) {
System.out.println(field.getName());
}
通过method.invoke(obj, ...args)可以调用obj实例的method方法。
3、获取对应的实例构造器,并生成类实例
代码块
Class class_dog = Dog.class;
Constructor constructor = class_dog.getConstructor(String.class, int.class);
constructor.newInstance("Tom", 10);
如果没有显示的声明默认构造器,class_dog.getConstructor()会抛出NoSuchMethodException异常。
4、通过newInstance()方法生成类实例
代码块
Class<Check> checkClass1 = Check.class;
Check check1 = checkClass1.newInstance();
5、设置私有变量
代码块
Class<Check> checkClass1 = Check.class;
Field auditId = checkClass1.getDeclaredField("auditId");
Check check1 = checkClass1.newInstance();
auditId.setAccessible(true);
auditId.set(check1,123);