反射
1.万恶之源-Class 类型
1.1 概述
Java 中所有的类都是一个模版
所有的类看作一个整体,这个整体对于 Java 而言是一个【类的类型】 Class 类型
Class 类型对象是对应 Java 类型在内存【方法区】空间内容。
class ClassName {
Field[] fields; // 成员变量 Field 类型数组,成员变量有多个,有一个,或者没有
Constructor[] constructors; // 构造方法 Constructor 类型数组,构造方法至少有一个,可能允许多个
Method[] methods; // 成员方法 Method 类型数组,成员方法可以是一个,多个或者没有
}
1.2 Class 类型对象获取方法
Class<?> Class.forName(String packageAndClassName);Class 类提供的静态成员方法,根据用户提供的完整的包名.类名,获取对应数据类型的 Class 对象。
Class<? extends T> 任意类对象.getClass();Java 中任意一个类对象,都可以通过 getClass 方法获取对应的 Class 类型对象。该方法是 Object 类提供给 Java 中所有类型使用的方法
Class<T> 类名.class;通过 Java 中任意的类名,获取其属性内容,得到对应的 Class 对象。
1.3 Class 相关案例代码
三种方式创建Class对象同时判断这三个对象是否是同一个
public class Person {
public static void main(String[] args) throws ClassNotFoundException {
/*
1. Class<?> Class.forName(String packageAndClassName);
最常用,也是【工厂模式】的核心方法。
*/
Class<?> c1 = Class.forName("com.mjl.reflect.Person");
/*
2. Class<? extends T> 任意类对象.getClass();
常用于类型判断,类型校验
*/
Person person = new Person();
Class<? extends Person> c2 = person.getClass();
/*
3. Class<T> 类名.class;
常用于类型约束,主要用于反射【方法操作】,类型转换操作
*/
Class<Person> c3 = Person.class;
/*
以上三个 Class 对象是否为同一个对象???
无论通过哪一种形式获取的 Class 对象,只要是同一个类型,得到的都是
同一个 Class 对象,对应的是内存【方法区】的同一个数据空间。
*/
System.out.println(c1 == c2);//true
System.out.println(c3 == c2);//true
System.out.println(c1 == c3);//true
}
}
2.反射操作实例化对象 - Constructor 构造方法类型
2.1 概述
对于 Class 对象,构造方法的名称是【类名】,不具备唯一性。在实际调用构造方法,区分构造方法的不同是通过
【参数列表,参数数据类型,参数个数,参数顺序】来区分!!!
2.2 通过 Class 对象获取对应的 Constructor 构造方法对象
Constructor[] getConstructors();获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组
// 核心方法 ★ Constructor getConstructor(Class... parameterTypes);根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,并且是【非私有化】构造方法
Constructor[] getDeclaredConstructors();【暴力反射】获取当前 Class 对应数据类型的所有构造方法对象数组,包括【私有化构造方法】
Constructor getDeclaredConstructor(Class... parameterTypes);【暴力反射】根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,可以获取私有化构造方法
代码示例:
public class Person {
//属性
private int age;
private String name;
public int test = 10;
public static int testStatic = 10;
//构造方法 Constructor
public Person() {}
public Person(int age) {
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
//成员方法
}
public void game() {
System.out.println("大吉大利,腾讯倒闭");
}
public void game(String name) {
System.out.println("玩" + name);
}
private void testPrivate() {
System.out.println("类内私有化成员方法!!!");
}
private void testPrivate(String str) {
System.out.println("吃" + str);
}
public static void test() {
System.out.println("静态!!!");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// 获取指定类型的 Class 对象
Class<?> cls = Class.forName("com.mjl.reflect.Person");
// 获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组
Constructor<?>[] constructors = cls.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println();
// 根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,并且是【非私有化】构造方法
Constructor<?> c1 = cls.getConstructor();
Constructor<?> c2 = cls.getConstructor(int.class);
Constructor<?> c3 = cls.getConstructor(int.class, String.class);
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
// 【暴力反射】获取当前 Class 对应数据类型的所有构造方法对象数组,包括【私有化构造方法】
Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println();
// 【暴力反射】根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,可以获取私有化构造方法
Constructor<?> c4 = cls.getDeclaredConstructor(String.class);
System.out.println(c4);
}
}
2.3 Constructor 对象实例化对象操作
使用方法
Object newInstance(Object... parameterValues); // 重点方法 ★通过 Constructor 构造方法对象调用 newInstance 进行实例化对象操作,当前 newInstance 方法所需参数是构造方法参数列表对应的实际参数,采用的参数形式为 Object… 支持任意类型的不定长参数。可以支持没有参数,一个参数或者多个参数,在方法内部是一个 Object 类型的数组
代码示例:
Constructor<?> c2 = c1s.getConstructor(int.class, String.class);
Person person = (Person)c2.newInstance(12,"张三");
System.out.println(person);
3.反射操作核心 - Method
3.1 概述
Method 成员方法类型,通过 Class 对象获取关注点是【方法名】和【形式参数列表】
3.2 通过 Class 对象获取对应的 Method 成员方法对象
Method[] getMethods();可以获取 Class 对象对应类型的所有非私有化成员方法对象数组,包括父类继承给子类可以供子类使用的成员方法
// 核心方法 ★ Method getMethod(String methodName, Class... parameterTypes);根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,只能是非私有化成员方法和父类继承给子类使用的方法。
Method[] getDeclaredMethods();【暴力反射】可以获取 Class 对象对应类型的所有成员方法对象数组,包括私有化成员方法,但是不包括继承方法父类的成员方法。有且只有子类自身方法
Method getDeclaredMethod(String methodName, Class... parameterTypes);【暴力反射】根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,包括私有化成员方法,不包括父类继承到子类的方法。仅获取子类自有方法
代码示例:
public class MethodTest {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 获取指定类型的 Class 对象
Class<?> cls = Class.forName("com.mjl.reflect.Person");
// 可以获取 Class 对象对应类型的所有非私有化成员方法对象数组,包括父类继承给子类可以供子类使用的成员方法
Method[] methods = cls.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
/*
【暴力反射】可以获取 Class 对象对应类型的所有成员方法对象数组,包括私有化成员方法,但是不包括继承方法父类的成员方法。
有且只有子类自身方法
*/
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println();
/*
根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,
只能是非私有化成员方法和父类继承给子类使用的方法。
*/
Method game1 = cls.getMethod("game");
Method game2 = cls.getMethod("game", String.class);
System.out.println(game1);
System.out.println(game2);
System.out.println();
/*
【暴力反射】根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,包括私有化成员方法,
不包括父类继承到子类的方法。仅获取子类自有方法
*/
Method m1 = cls.getDeclaredMethod("testPrivate");
Method m2 = cls.getDeclaredMethod("testPrivate", String.class);
System.out.println(m1);
System.out.println(m2);
}
}
4.3 Method 成员方法对象执行对应方法操作
通过 Method 对象使用以下方法,执行对应方法运行目标
Object invoke(Object obj, Object... parameterValues); // 重点方法 ★第一个参数 obj 执行当前方法的调用者,静态成员方法可以直接对应类实例化对象,或者 null
第二个参数是当前方法所需的实际参数列表,采用 Object 不定长参数形式,不限制任何的参数类型
【重点】
invoke 方法返回值类型为 Object 类型,支持当前目标方法的返回值,如果执行目标方法没有返回值,invoke 最终返回 null
代码示例:
// 实例化对象
Object o = cls.getConstructor().newInstance();
// 非私有化成员方法
game1.invoke(o);
game2.invoke(o, "PUBG");
// 私有化成员方法赋予操作权限之后操作
System.out.println();
m1.setAccessible(true);
m2.setAccessible(true);
m1.invoke(o);
m2.invoke(o, "饺子");
4. 反射操作数据存储和获取 - Field
4.1 概述
针对于类内的成员变量,唯一的标识【成员变量名】
4.2 通过 Class 对象获取对应的 Field 成员变量对象
Field[] getFields();获取类内所有非私有化成员变量对象数组
Field[] getDeclaredFields(); // 重点方法 ★【暴力反射】获取类内所有成员变量对象数组,包括私有化成员变量对象
Field getField(String fieldName);根据指定的成员变量名称,获取对应的非私有化成员变量对象、
Field getDeclaredField(String fieldName); // 重点方法 ★【暴力反射】根据指定的成员变量名称,获取对应的成员变量对象,包括私有化成员变量
代码示例:
public int test = 10;
private String name;
private int age;
main() {
Class<?> cls = Class.forName("com.mjl.reflect.Person");
Field f = cls.getField("test");
Field f1 = cls.getDeclaredField("name");
}
4.3 Field 对象操作获取数据和赋值数据
赋值操作方法
void set(Object obj, Object value); // 重点方法 ★第一个参数 obj 是当前成员变量到底是哪一个类对象。
第二个参数 value 是给予当前成员变量的赋值的数据内容,考虑符合成员变量的数据类型
取值操作
Object get(Object obj); // 重点方法 ★第一个参数 obj 是当前成员变量到底是哪一个类对象。
返回值类型是当前成员变量存储的数据情况,统一返回 Object 类型,根据所需强转目标数据类型
5.暴力反射权限问题解决
对应方法
void setAccessible(boolean flag); // 重点方法 ★反射操作中 Constructor, Method ,Field 对象都可以调用该方法解决 私有化反射对象权限操作问题
参数提供为 true 当前私有化构造方法对象有对应的操作权限。
public static void setAccessible(AccessibleObject[] array, boolean flag) // 重点方法 ★AccessibleObject 类工具方法,所需参数是 AccessibleObject 数组和对应的权限标记,flag 通常为 true。
Field Method Constructor 都是 AccessibleObject 子类
本文介绍了Java中的反射机制,包括Class类型的概念和获取方法,如何通过Constructor构造方法实例化对象,Method成员方法的获取及执行,以及Field成员变量的访问和赋值。还讨论了暴力反射用于访问私有成员以及解决权限问题的setAccessible方法。

2万+

被折叠的 条评论
为什么被折叠?



