① 当虚拟机启动,先初始化main方法所在的类
② new 一个类的对象
③ 调用类的静态成员(除了final常量)和静态方法
④ 使用java.lang.reflect包的方法对类进行反射调用
⑤ 当初始化一个类,如果其父类没有被初始化,则会初始化它的父类
类的被动引用(不会发生类的初始化)
① 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类的初始化
② 通过数组定义类引用,不会触发该类的初始化
③ 引用常量不会触发该类的初始化(常量在链接阶段就存入调用类的常量池中了)
代码示例
public class ReflectDemo {
static {
System.out.println("Main 类被加载...");
}
public static void main(String[] args) throws ClassNotFoundException {
// 1、主动引用
Son son = new Son();
// 2、反射也会产生主动引用
Class.forName("test.Son");
// 不会产生类的引用的方法
// 1、通过子类引用父类的静态变量,不会导致子类的初始化
System.out.println(Son.b);
// 2、通过数组定义类引用,不会触发该类的初始化
Son[] array = new Son[10];
}
}
class Father {
static {
System.out.println("父类被加载...");
}
static int b = 8;
}
class Son extends Father {
static {
System.out.println("子类被加载...");
m = 300;
}
static int m = 100;
static final int M = 10;
}
通过反射获取运行时类的完整结构:Field、Method、Constructor、Superclass、Interface、Annotation
① 实现的全部接口
② 所继承的父类
③ 全部的构造器
④ 全部的方法
⑤ 全部的Field
⑥ 注解
......
代码示例
public class ClassInformationDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class clazz = Class.forName("test.User");
// 获取包名+类名
System.out.println(clazz.getName());
// 获取类名
System.out.println(clazz.getSimpleName());
System.out.println("===========获取全部public的属性==============");
// 获取类的属性
// 获取全部public的属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==========获取全部的属性===============");
// 获取全部的属性
fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("============获取指定属性的值=============");
// 获取指定属性的值
Field name = clazz.getDeclaredField("name");
System.out.println(name);
// 获取全部的方法
System.out.println("============获取本类及其父类的全部public方法=============");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===========获取本类的全部的方法==============");
methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===========获取指定的方法============");
Method method = clazz.getMethod("getName", null);
System.out.println(method);
System.out.println("===========获取类的全部public构造器=============");
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("===========获取类的全部构造器=============");
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
}
class User {
String name;
int age;
User(){
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
private void test() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
动态创建对象
创建类的对象:调用Class对象的newInstance()方法
① 类必须有一个无参构造器
② 类的构造器的访问权限需要足够
难道没有无参的构造器就不能创建对象了吗?
只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
步骤如下:
① 通过Class类的getDeclaredConstructor(Class ... parameterTypes)取得本类的制度形参类型的构造器
② 向构造器的形参中传递一个对象数组进去,里面包含了构造器所需的各个参数
③ 通过Constructor实例化对象
调用指定的方法
通过反射,调用类中的方法,通过Method类完成。
① 通过Class类的getMethod(String name, Class...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型
② 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。