反射 Reflection 被视为动态语言的关键。
反射机制允许Java程序在运行时获取一个类的所有信息,包括任何定义的信息(成员变量,成员方法,构造方法等),并且可以对类的字段、方法、构造方法等进行操作。
Java虚拟机需要加载一个类,会变成 .class 文件(字节码文件),这里存的是类的所有的信息。Java可以通过反射将字节码文件变成一个对象: Class对象
先来看一个入门案例:
package com.qf.test_Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo1 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.将Person.class这个文件 变成一个class对象
Class<Person> personClass = Person.class;
System.out.println(personClass);
//2.将Person类的无参构造方法变成一个对象 constructor
Constructor<Person> constructor = personClass.getConstructor();
//3.通过构造方法创建对象
Person person = constructor.newInstance();
}
}
总结步骤:
1.获取字节码文件对象(Person.class)
2.通过字节码文件获取构造方法对象 3.通过构造方法对象创建Person类对象
1.获取class对象
对于Java文件的Person.class文件,Java可以将它转换成Class对象,怎样获取这样的Class对象呢,主要有三种方式:
package com.qf.test_Reflection;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
//1.类.class 获取类对应的 Class对象
Class<Person> personClass = Person.class;
System.out.println(personClass);
//2.Class.forName() 通过类的 全限定名字 获取类对应的Class对象
Class<?> aClass = Class.forName("com.qf.test_Reflection.Person");
System.out.println(aClass);
//3.通过 对象.getClass() 来创建对应的类的Class对象
Class<? extends Person> aClass1 = new Person().getClass();
System.out.println(aClass1);
}
}
Class对象获取方法总结:
1.类.class 获取类对应的 Class对象
2.Class.forName() 通过类的 全限定名字 获取类对应的Class对象
3.通过 对象.getClass() 来创建对应的类的Class对象
这一步结束,已经获取了Person.class字节码文件的Class对象。Person.class字节码文件,存了好多的类的信息 接着就是要将这些信息取出来
2.获取Constructor对象
通过Class对象调用方法获取构造方法:
返回类型 | 方法 |
---|---|
Constructor<?>[] | getConstructors() 返回一个包含Constructor 对象的数组,反射由此表示的类的所有 公共构造方法 |
Constructor<?>[] | getDeclaredConstructors() 返回一个包含 反映 Constructor 对象表示的类声明的所有 Constructor 对象 的数组 类 。 |
Constructor<T> | getConstructor(类<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类的指定的公共 类 函数。 |
Constructor<T> | getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类或接口的指定 类 函数。 |
以上是Class对象调用,获取构造方法的方法
方法名 | 意义 |
---|---|
newInstance(Object... initargs) | 使用此 Constructor 对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。 |
以上是Constructor调用,创建新实例的方法
package com.qf.test_Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取类的Class对象
Class<Person> personClass = Person.class;
//2.通过Class对象获取下面的构造方法对象
//(1)获取 所有的公开的 构造方法
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("==========");
//(2)获取 所有的 构造方法
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("==========");
//(3)获取 无参公开的构造方法(一个公开的构造方法)//多个参数 中间使用,隔开即可
Constructor<Person> constructor = personClass.getConstructor(null);
System.out.println(constructor);
System.out.println("==========");
//(4)获取 获取一个任意的构造方法
Constructor<Person> declaredConstructor1 = personClass.getDeclaredConstructor(String.class,int.class);
System.out.println(declaredConstructor1);
System.out.println("==========");
//构造方法已经获取,接下来咋办? 使用构造方法对象 创建实例
Person person = declaredConstructor1.newInstance("绫华",18);
System.out.println(person.name);
System.out.println(person.age);
}
}
3.获取Method对象
返回值 | 方法 |
---|---|
方法[] | getMethods() 返回一个包含方法 对象的数组,反射由此类 对象表示的类或接口的所有公共方法,包括那些由类或接口和那些从超类和超接口继承的声明。 |
方法[] | getDeclaredMethods() 返回一个包含方法 对象的数组,反射的类或接口的所有声明的方法,通过此 类 对象表示的,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。 |
方法 | getMethod(String name, 类<?>... parameterTypes) 返回一个 方法 对象,它反映此类 对象表示的类或接口的指定的公共成员方法 。 |
方法 | getDeclaredMethod(String name, 类<?>... parameterTypes) 返回一个 方法 对象,它反映此类 对象表示的类或接口的指定声明的方法。 |
以上是Class对象调用,获取方法的方法
方法名 | 意义 |
---|---|
Object invoke(Object obj, Object ...args); | 使用方法对象调用invoke,方法会执行的 |
以上是Method对象调用方法 方法会执行
package com.qf.test_Reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Method11 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取Class对象
Class<Person> personClass = Person.class;
//2.通过Class对象获取下面的方法对象
//(1)获取所有的公开的方法 和父类公开的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("==========");
//(2)获取所有的方法
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("==========");
//(3)获取一个任意的方法(自己的或父类的)
Method play = personClass.getMethod("play",String.class,int.class);
System.out.println(play);
System.out.println("==========");
//(4)获取一个私有化的方法(自己的)
Method eat = personClass.getDeclaredMethod("eat",String.class);
System.out.println(eat);
System.out.println("==========");
//获取方法之后,方法调用
//第一个参数 此方法在哪个对象下面
//第二个参数 是方法有可能有参数,传的是实参
Person person = personClass.getConstructor().newInstance();
play.invoke(person,"胡桃",17);
//可以通过暴力反射 设置方法或者属性的权限问题
eat.setAccessible(true);
eat.invoke(person,"绫华");//私有方法
}
}
4.获取Field对象
返回值 | 方法 |
---|---|
Field[] | getFields() 返回一个包含Field 对象的数组,反射由此类 对象表示的类或接口的所有可访问的公共字段(属性)。 |
Field[] | getDeclaredFields() 返回一个包含Field 对象的数组,反映此类 对象表示的类或接口声明的所有字段。 |
Field | getField(String name) 返回一个 Field 对象,它反映此类 对象表示的类或接口的指定公共成员字段。 |
Field | getDeclaredField(String name) 返回一个 Field 对象,它反映此类 对象表示的类或接口的指定已声明字段。 |
以上是Class对象调用的方法,获取属性(字段)的方法
返回值 | 方法 |
---|---|
void | set(Object obj, Object value) 将value值赋值给obj下面的属性 |
以上是Field对象调用的方法,为属性赋值
package com.qf.test_Reflection;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Field11 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<Person> personClass = Person.class;
//1.获取所有的公开的属性对象
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==========");
//2.获取所有的属性对象
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("==========");
//3.获取单个公开的属性对象
Field name = personClass.getField("name");
System.out.println(name);
System.out.println("==========");
//4.获取单个任意的属性对象
Field sex = personClass.getDeclaredField("sex");
System.out.println(sex);
System.out.println("==========");
//属性获取完以后? 赋值
Person person = personClass.getConstructor().newInstance();
name.set(person,"派蒙");
System.out.println(name.get(person));
sex.setAccessible(true);
sex.set(person,true);//私有变量,暴力反射 设置方法或者属性的权限问题
System.out.println(sex.get(person));
}
}