JavaSE——反射
目录
一、反射的概念
二、获取class对象的三种方式
三、使用反射获取构造方法
(一)Class类中用于获取构造方法的方法
1.获取所有公共构造方法
2.获取所有构造方法
3.获取单个公共构造方法对象
4.获取单个构造方法对象
(二)Constructor类中用于创建对象的方法
四、使用反射获取成员变量
(一)Class类中用于获取成员变量的方法
(二)Field类中用于创建对象的方法
五、使用反射获取成员方法
(一)Class类中用于获取成员方法的方法
(二)Method类中用于创建对象的方法
六、反射的作用
(一)使用反射保存任意对象数据
(二)反射结合配置文件,动态地创建对象并调用方法
一、反射的概念
反射是Java的一种能力,它允许程序在运行时检查和操作自身的结构和行为。通过反射,可以获取类的信息(如字段、方法、构造函数等),并可以动态地调用方法、访问字段等。反射是通过java.lang.reflect包中的类和接口来实现的。
二、获取class对象的三种方式
- 在源代码阶段,即此时只有.java和.class文件:使用Class.forName("全类名")
- 在加载阶段,此时将.class文件加载到内存中:使用类名.class
- 在运行阶段,此时创建了类的实例对象:使用对象.getClass()
Student类:
@Data
public class Student {private String name;private int age;public Student() {}public Student(String name) {this.name = name;}protected Student(int age) {this.age = age;}private Student(String name, int age) {this.name = name;this.age = age;}
}
public class MyReflectDemo1 {public static void main(String[] args) throws ClassNotFoundException {// 方式一:最常用Class clazz1 = Class.forName("com.testdemo.Student");System.out.println(clazz1);// 方式二:经常当做参数来传递Class clazz2 = Student.class;// 方式三:有了这个类的对象时,才可以使用Student student = new Student();Class clazz3 = student.getClass();System.out.println(clazz1 == clazz2); // trueSystem.out.println(clazz1 == clazz3); // trueSystem.out.println(clazz2 == clazz3); // true}
}
三、使用反射获取构造方法
(一)Class类中用于获取构造方法的方法
方法名 | 作用 |
---|---|
Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回单个公共构造方法对象 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造方法对象 |
1.获取所有公共构造方法
Class clazz = Class.forName("com.testdemo.Student");
Constructor[] conn1 = clazz.getConstructors();
for (Constructor constructor : conn1) {System.out.println(constructor);
}
/*** public com.testdemo.Student(java.lang.String)* public com.testdemo.Student()*/
2.获取所有构造方法
Constructor[] conn2 = clazz.getDeclaredConstructors();
for (Constructor constructor : conn2) {System.out.println(constructor);
}
/*** private com.testdemo.Student(java.lang.String,int)* protected com.testdemo.Student(int)* public com.testdemo.Student(java.lang.String)* public com.testdemo.Student()
3.获取单个公共构造方法对象
Constructor conn3 = clazz.getConstructor();
System.out.println(conn3);
// public com.testdemo.Student()Constructor conn4 = clazz.getConstructor(String.class);
System.out.println(conn4);
// public com.testdemo.Student(java.lang.String)
4.获取单个构造方法对象
Constructor conn5 = clazz.getDeclaredConstructor();
System.out.println(conn5);
// public com.testdemo.Student()Constructor conn6 = clazz.getDeclaredConstructor(String.class);
System.out.println(conn6);
// public com.testdemo.Student(java.lang.String)System.out.println(conn6.getModifiers());
// public修饰的构造方法,返回1Constructor conn7 = clazz.getDeclaredConstructor(int.class);
System.out.println(conn7);
// protected com.testdemo.Student(int)System.out.println(conn7.getModifiers());
// protected修饰的构造方法,返回4Constructor conn8 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(conn8);
// private com.testdemo.Student(java.lang.String,int)System.out.println(conn8.getModifiers());
// private修饰的构造方法,返回2// 获取构造方法的每个参数
Parameter[] parameters = conn8.getParameters();
for (Parameter parameter : parameters) {System.out.println(parameter);
}
/*** java.lang.String arg0* int arg1* */
(二)Constructor类中用于创建对象的方法
方法名 | 作用 |
---|---|
T newInstance(Object... initargs) | 根据指定的构造方法创建对象 |
setAccessible(boolean flag) | 设置为true,表示取消访问检查 |
// 利用获取到的构造方法,创建类的对象
// 暴力反射:临时取消权限校验
conn8.setAccessible(true);
Student newInstance = (Student) conn8.newInstance("张三", 26);
System.out.println(newInstance);
// Student(name=张三, age=26)
四、使用反射获取成员变量
Student类:
@Data
public class Student {private String name;private int age;public String gender;public double store;public Student() {}public Student(String name, int age, String gender, double store) {this.name = name;this.age = age;this.gender = gender;this.store = store;}
}
(一)Class类中用于获取成员变量的方法
方法名 | 作用 |
---|---|
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量对象 |
Field getDeclaredField(String name) | 返回单个成员变量对象 |
Class clazz = Class.forName("com.testdemo.myreflect3.Student");
// 1.获取所有公共的成员变量
Field[] fields1 = clazz.getFields();
for (Field field : fields1) {System.out.println(field);
}
/*** public java.lang.String com.testdemo.myreflect3.Student.gender* public double com.testdemo.myreflect3.Student.store*/// 2.获取所有的成员变量
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {System.out.println(field);
}
/*** private java.lang.String com.testdemo.myreflect3.Student.name* private int com.testdemo.myreflect3.Student.age* public java.lang.String com.testdemo.myreflect3.Student.gender* public double com.testdemo.myreflect3.Student.store*/// 3.获取单个公共的成员变量
Field field3 = clazz.getField("gender");
System.out.println(field3);
// public java.lang.String com.testdemo.myreflect3.Student.genderField field4 = clazz.getField("store");
System.out.println(field4);
// public double com.testdemo.myreflect3.Student.store// 4.获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
// private java.lang.String com.testdemo.myreflect3.Student.nameField age = clazz.getDeclaredField("age");
System.out.println(age);
// private int com.testdemo.myreflect3.Student.ageField gender = clazz.getDeclaredField("gender");
System.out.println(gender);
// public java.lang.String com.testdemo.myreflect3.Student.genderField store = clazz.getDeclaredField("store");
System.out.println(store);
// public double com.testdemo.myreflect3.Student.store// 获取成员变量的权限修饰符
System.out.println(store.getModifiers()); // 1// 获取成员变量的名字
System.out.println(store.getName()); // store// 获取成员变量的数据类型
System.out.println(store.getType()); // double
(二)Field类中用于创建对象的方法
方法名 | 作用 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
// 获取成员变量记录的值
// 暴力反射:临时取消权限校验
name.setAccessible(true);
Student student = new Student("张三", 18, "男", 98.5);
String value = (String) name.get(student);
System.out.println(value); // 张三// 修改对象的属性值
name.set(student,"李四");
System.out.println(student);
// Student(name=李四, age=18, gender=男, store=98.5)
五、使用反射获取成员方法
Student类:
@Data
public class Student {private String name;private int age;public void sleep() {System.out.println("睡觉");}public void sleep(String someone) {System.out.println(someone + "在睡觉");}public void eat() {System.out.println("吃东西");}private String eat(String something) throws IOException, NullPointerException, ClassCastException {System.out.println("在吃" + something);return "菜单";}private void eat(String something, int a) {System.out.println("在吃" + something);}
}
(一)Class类中用于获取成员方法的方法
方法 | 作用 |
---|---|
Method[] getMethods() | 返回所有公共成员方法对象的数组,包括继承的 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,不包括继承的 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象 |
Class clazz = Class.forName("com.testdemo.myreflect4.Student");
// 1.获取所有公共的成员方法(包含父类中所有的公共方法)
Method[] methods = clazz.getMethods();
for (Method method : methods) {System.out.println(method);
}
/*** public java.lang.String com.testdemo.myreflect4.Student.getName()* public boolean com.testdemo.myreflect4.Student.equals(java.lang.Object)* public java.lang.String com.testdemo.myreflect4.Student.toString()* public int com.testdemo.myreflect4.Student.hashCode()* public void com.testdemo.myreflect4.Student.sleep()* public void com.testdemo.myreflect4.Student.sleep(java.lang.String)* public void com.testdemo.myreflect4.Student.setName(java.lang.String)* public void com.testdemo.myreflect4.Student.setAge(int)* public void com.testdemo.myreflect4.Student.eat()* public int com.testdemo.myreflect4.Student.getAge()* public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException* public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException* public final void java.lang.Object.wait() throws java.lang.InterruptedException* public final native java.lang.Class java.lang.Object.getClass()* public final native void java.lang.Object.notify()* public final native void java.lang.Object.notifyAll()* public void com.testdemo.myreflect4.Student.sleep(java.lang.String)*/// 2.获取所有的成员方法(不包含父类的成员方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);
}
/*** public java.lang.String com.testdemo.myreflect4.Student.getName()* public boolean com.testdemo.myreflect4.Student.equals(java.lang.Object)* public java.lang.String com.testdemo.myreflect4.Student.toString()* public int com.testdemo.myreflect4.Student.hashCode()* public void com.testdemo.myreflect4.Student.sleep()* public void com.testdemo.myreflect4.Student.sleep(java.lang.String)* public void com.testdemo.myreflect4.Student.setName(java.lang.String)* public int com.testdemo.myreflect4.Student.getAge()* public void com.testdemo.myreflect4.Student.setAge(int)* protected boolean com.testdemo.myreflect4.Student.canEqual(java.lang.Object)* private void com.testdemo.myreflect4.Student.eat(java.lang.String,int)* public void com.testdemo.myreflect4.Student.eat()* private java.lang.String com.testdemo.myreflect4.Student.eat(java.lang.String) throws java.io.IOException,java.lang.NullPointerException,java.lang.ClassCastException* public void com.testdemo.myreflect4.Student.sleep(java.lang.String)*/// 3.获取单个公共的成员方法对象
Method sleep = clazz.getMethod("sleep", String.class);
System.out.println(sleep);
// public void com.testdemo.myreflect4.Student.sleep(java.lang.String)// 4.获取单个成员方法对象
Method eat = clazz.getDeclaredMethod("eat", String.class, int.class);
System.out.println(eat);
// private void com.testdemo.myreflect4.Student.eat(java.lang.String,int)Method eat1 = clazz.getDeclaredMethod("eat", String.class);
System.out.println(eat1);
// private java.lang.String com.testdemo.myreflect4.Student.eat(java.lang.String)
// throws java.io.IOException,java.lang.NullPointerException,java.lang.ClassCastException// 获取无参的成员方法
Method eat2 = clazz.getDeclaredMethod("eat");
System.out.println(eat2);
// public void com.testdemo.myreflect4.Student.eat()// 获取方法的修饰符
int modifiers = eat1.getModifiers();
System.out.println(modifiers); // 2// 获取方法的名字
String name = eat1.getName();
System.out.println(name); // eat// 获取方法的形参
Parameter[] parameters = eat1.getParameters();
for (Parameter parameter : parameters) {System.out.println(parameter);
}
// java.lang.String arg0// 获取方法抛出的异常
Class[] exceptionTypes = eat1.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);
}
/*** class java.io.IOException* class java.lang.NullPointerException* class java.lang.ClassCastException*/
(二)Method类中用于创建对象的方法
方法 | 作用 |
---|---|
Object invoke(Object obj, Object... args) | 运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
// 方法运行
Student student = new Student();
eat1.setAccessible(true);
String result = (String) eat1.invoke(student, "汉堡包");
System.out.println(result);
// 在吃汉堡包
// 菜单
六、反射的作用
- 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
- 结合配置文件,动态地创建对象并调用方法
(一)使用反射保存任意对象数据
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去。
创建Cat类:
@Data
@AllArgsConstructor
public class Cat {private String ownerName;private String catName;private int age;private String breed;
}
创建Fish类:
@Data
@AllArgsConstructor
public class Fish {private int age;private String breed;
}
创建测试类:
public class TestDemo {public static void main(String[] args) throws IllegalAccessException, IOException {Cat cat = new Cat("张三", "咪咪", 2, "奶牛猫");Fish fish = new Fish(1, "鲤鱼");saveObjects(cat);saveObjects(fish);}private static void saveObjects(Object obj) throws IllegalAccessException, IOException {BufferedWriter bw = new BufferedWriter(new FileWriter("chapter19\\src\\com\\testdemo\\myreflect5\\a.txt",true));// 获取字节码文件的对象Class clazz = obj.getClass();// 获取所有的成员变量Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);// 获取属性名字String name = field.getName();// 获取属性值Object value = field.get(obj);// 写入文件bw.write(name + "=" + value);bw.newLine();}bw.close();}
}
运行结果:
(二)反射结合配置文件,动态地创建对象并调用方法
Student类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private int age;public void study(){System.out.println("学生在学习!");}
}
Teacher类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {private String name;private double salary;public void teach() {System.out.println("老师在教书!");}
}
prop.properties:
classname=com.testdemo.myreflect6.Student
method=study
测试类:
public class MyReflectDemo {public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException {// 1.加载配置文件Properties properties = new Properties();FileInputStream fis = new FileInputStream("chapter19\\src\\com\\testdemo\\myreflect6\\prop.properties");properties.load(fis);fis.close();System.out.println(properties);// 2.获取全类名和方法名String classname = properties.getProperty(Constant.CLASS_NAME);String method = properties.getProperty(Constant.METHOD);// 3.获取字节码文件Class clazz = Class.forName(classname);// 4.获取构造方法Constructor constructor = clazz.getDeclaredConstructor();// 5.通过构造方法拿到对象Object obj = constructor.newInstance();System.out.println(obj);// Student(name=null, age=0)// 6.获取成员方法Method declaredMethod = clazz.getDeclaredMethod(method);// 6.1暴力反射:临时取消权限校验declaredMethod.setAccessible(true);// 7.执行成员方法:因为该成员方法是无参的,所以不需要传递第二个参数declaredMethod.invoke(obj);// 学生在学习!}
}interface Constant {String CLASS_NAME = "classname";String METHOD = "method";
}
要想创建Teacher对象,并调用Teacher的成员方法,只需要修改prop.properties文件中的配置信息即可:
classname=com.testdemo.myreflect6.Teacher
method=teach
修改配置文件后的运行结果:
Teacher(name=null, salary=0.0)
老师在教书!