Java反射
2022-11-19 本文已影响0人
h2coder
概述
在程序的运行过程中, 通过Class对象得到类中的信息(构造方法,成员方法,成员变量), 并操作他们。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
-
反射的应用场景
- IDEA的智能提示
- 框架 Spring、SpringMVC、Mybatis 等的底层原理
-
利用反射调用它类中的属性和方法时,无视修饰符。
-
使用反射创建对象,代码更复杂,功能更强大灵活。
Class对象
在Java中有一个类,类名就叫Class。Class类创建的对象我们成为Class对象
public class Class<T> {
保存类中的信息(构造方法, 成员方法, 成员变量)
}
- 类结构
Class对象会保存类中的信息(构造方法, 成员方法, 成员变量等)
有了Class对象就能得到类中的所有信息。可以说得到Class对象反射就完成了一半。
class Class {
//成员变量
Field[] fs;
//构造器
Constructor[] cs;
//成员方法
Method[] ms;
}
获取Class对象的方式
三种获取Class对象的方式
- 对类名.class
Class<Person> clazz1 = Person.class;
- 对象.getClass()
Person p = new Person();
Class<? extends Person> clazz2 = p.getClass();
- Class.forName("类全名");
Class<?> clazz3 = Class.forName("com.zh.reflection.model.Person");
测试的实体类
class A {
public int a;
}
public class Person extends A {
public int aa;
//成员变量
private String name;
private int age;
//-------构造方法-------
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
protected Person(int age) {
this.age = age;
}
//-----------------------
//-------get和set方法-------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//-------其他成员方法-------
public void add(int a, int b) {
int c = a + b;
System.out.println("相加结果:" + c);
}
private int work(int hour) {
System.out.println("一天工作" + hour + "小时");
return hour * 100; //工资
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
准备工作
- 使用反射,先要获取Class对象
//获取Person类的字节码对象
Class<Person> clazz = Person.class;
反射构造方法(Constructor)
Class类中获取构造方法
- Constructor<?>[] getConstructors():返回public修饰的所有构造方法对象的数组
//获取所有公开public修饰的构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
- Constructor<T> getConstructor(Class<?>... parameterTypes):返回public修饰的单个构造方法对象
//无参构造,getConstructor():公开修饰的
Constructor<Person> c2 = clazz.getConstructor();
System.out.println(c2);
- Constructor<?>[] getDeclaredConstructors():返回任意权限的所有构造方法对象的数组
//获取所有任意权限的构造方法
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
- Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回任意权限的单个构造方法对象
//无参构造,getDeclaredConstructor():任意权限修饰的
Constructor<Person> c2 = clazz.getDeclaredConstructor();
System.out.println(c2);
- 获取带参构造方法
//获取带参构造方法
Constructor<Person> c3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(c3);
反射构造方法创建对象
Constructor类中用于创建对象的方法
- Constructor类中的方法
- T newInstance(Object... initargs):根据指定的构造方法创建对象
- setAccessible(boolean flag):设置为true,表示允许对私有权限的访问
//反射获取无参构造方法
Constructor<Person> c1 = clazz.getConstructor();
//使用构造器创建对象
Person p1 = c1.newInstance();
System.out.println(p1);
//反射获取有参的构造方法,newInstance() 要传入实参
Constructor<Person> c2 = clazz.getConstructor(String.class, int.class);
Person p2 = c2.newInstance("张三", 18);
System.out.println(p2);
//反射获取私有的带参构造方法
Constructor<Person> c3 = clazz.getDeclaredConstructor(String.class);
//设置权限为允许范围,只针对对非空开
c3.setAccessible(true);
Person p3 = c3.newInstance("李四");
System.out.println(p3);
反射方法(Method)
Class类中获取成员方法
- Method[] getMethods():返回所有public的成员方法对象的数组,包括继承的。
//获取所有公开public的方法(包括从父类继承而来的public方法)
Method[] ms1 = clazz.getMethods();
for (Method method : ms1) {
System.out.println(method);
}
- Method getMethod(String name, Class<?>... parameterTypes) :返回单个public的成员方法对象(参数name:表示方法名 ;参数parameterTypes:表示方法的形参类型)
//获取公开的成员方法
Method ms3 = clazz.getMethod("add", int.class, int.class);
System.out.println(ms3);
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
//获取所有任意权限的方法(不包括父类,只包含本类的)
Method[] ms2 = clazz.getDeclaredMethods();
for (Method method : ms2) {
System.out.println(method);
}
- Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象(参数name:表示方法名 ;参数parameterTypes:表示方法的形参类型)
//获取单个任意权限的成员方法
Method ms4 = clazz.getDeclaredMethod("add", int.class, int.class);
System.out.println(ms4);
反射成员方法并调用
-
Method类中的方法
- Object invoke(Object obj, Object... args)
- 参数obj:调用成员方法的对象。(如果调用的是静态方法,该参数为null即可)
- 参数args :可变参数,表示调用方法时传递的实参(如果没有就不写)
- 返回值Object :方法的返回值(如果没有就不用接)
- Object invoke(Object obj, Object... args)
-
先创建类实例,提供给后续反射调用方法
//反射创建对象实例
Constructor<Person> c1 = clazz.getConstructor();
Person person = c1.newInstance();
- 反射获取公开public成员方法
//反射获取公开public成员方法
Method ms1 = clazz.getMethod("add", int.class, int.class);
//调用成员方法,需传入实例对象和实参
ms1.invoke(person, 1, 2);
- 反射获取私有成员方法
//反射获取私有成员方法
Method ms2 = clazz.getDeclaredMethod("work", int.class);
//设置为公开访问
ms2.setAccessible(true);
Object result = ms2.invoke(person, 8);
System.out.println(result);
反射成员变量(Field)
Class类中获取成员变量
- Field getField(String name):返回单个公共成员变量对象
Field f1 = clazz.getField("aa");
System.out.println(f1);
- Field[] getFields():返回所有公共成员变量对象的数组,包括继承的public成员变量
//获取公开的成员变量(包括从父类中继承的公开的变量)
Field[] fs1 = clazz.getFields();
for (Field field : fs1) {
System.out.println(field);
}
- Field getDeclaredField(String name):返回单个成员变量对象
Field f2 = clazz.getDeclaredField("name");
System.out.println(f2);
- Field[] getDeclaredFields():返回所有本类成员变量对象的数组。不包括继承的
//获取任意权限的成员变量(只能是本类的,不包括父类的)
Field[] fs2 = clazz.getDeclaredFields();
for (Field declaredField : fs2) {
System.out.println(declaredField);
}
反射成员变量修改值、获取值
- Field类中的方法
- void set(Object obj, Object value):赋值。参数obj为成员变量所在的对象,参数value为成员变量的值
- Object get(Object obj) :获取值。参数obj为成员变量所在的对象
//获取单个成员变量
Field f1 = clazz.getDeclaredField("age");
System.out.println(f1);
//设置为可访问
f1.setAccessible(true);
//变量赋值,set(调用者、实参值)
f1.set(person, 18);
//变量取值,get(调用者)
Object age = f1.get(person);
System.out.println(age);