Java 反射
一. 概述
反射:加载类,并允许以编程的方式解剖类中的各个成分(成员变量、方法、构造器等等)
二. 获取类的字节码:Class对象
三种方式:
1. Class c1 = 类名.class:
2. 调用Class提供的方法:public static Class forName(String package)
3. Object提供的方法:public Class getClass(); Calss3 = 对象.getClass()
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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 static void main(String[] args) throws ClassNotFoundException {
Class c = Student.class;
System.out.println(c.getName());//全类名
System.out.println(c.getSimpleName());//简名 Student
Class c2 = Class.forName( "com.wyyzs.d01.Student");
System.out.println(c2.getName());
System.out.println(c2.getSimpleName());
Student student = new Student();
Class c3 = student.getClass();
System.out.println(c3.getName());
System.out.println(c3.getSimpleName());
}
三. 获取类的构造器
获取类的构造器
Class提供了从类中获取构造器的方法 | 说明 |
Constructor<?>[] getConstructors() | 获取全部构造器(只能获取public 修饰的) |
Constructor<?>[] getDeclaredConstructors() | 获取全部构造器(只要存在就能拿到) |
Constructor<?>[] getConstructor (Class<?>... parameterTypes) | 获取某个构造器(只能获取public修饰的) |
Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes) | 获取某个构造器(只要存在就能拿到) |
获取类构造器的作用
初始化对象返回
Constructor提供的方法 | 说明 |
T newInstance(Object... initargs) | 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) | 设置true,表示禁止检查访问控制(暴力反射) |
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private Student(String name) {
this.name = name;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void test1() throws Exception {
Class studentClass = Student.class;
//Constructor<?>[] getConstructors() 获取全部构造器(只能获取public 修饰的)
Constructor[] constructors = studentClass.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor.getName() + " " + constructor.getParameterTypes().length);
}
System.out.println("------------------------");
//Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor[] constructors2 = studentClass.getDeclaredConstructors();
for(Constructor constructor : constructors2){
System.out.println(constructor.getName() + " " + constructor.getParameterTypes().length);
}
System.out.println("------------------------");
//Constructor<?>[] getConstructor(Class<?>... parameterTypes) 获取某个构造器(只能获取public修饰的)
//无参
Constructor constructors3 = studentClass.getConstructor();
System.out.println(constructors3.getName() + " " + constructors3.getParameterTypes().length);
//有参
Constructor constructors4 = studentClass.getConstructor(String.class, int.class);
System.out.println(constructors4.getName() + " " + constructors4.getParameterTypes().length);
System.out.println("------------------------");
//Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)
//无参
Constructor constructors5 = studentClass.getDeclaredConstructor();
System.out.println(constructors5.getName() + " " + constructors5.getParameterTypes().length);
//有参
Constructor constructors6 = studentClass.getDeclaredConstructor(String.class);
System.out.println(constructors6.getName() + " " + constructors6.getParameterTypes().length);
Constructor constructors7 = studentClass.getDeclaredConstructor(String.class, int.class);
System.out.println(constructors7.getName() + " " + constructors7.getParameterTypes().length);
//T newInstance(Object... initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
//public void setAccessible(boolean flag) 设置true,表示禁止检查访问控制(暴力反射)
//调 constructors6 私有构造器 会报权限异常 此时 使用 setAccessible 设置true,表示禁止检查访问控制(暴力反射)
/* Student student = (Student) constructors6.newInstance();
System.out.println(student);*/
constructors6.setAccessible(true);
Student student2 = (Student) constructors6.newInstance("卡莎");
System.out.println(student2);
Student student3 = (Student) constructors7.newInstance("卡莎", 18);
System.out.println(student3);
}
四. 获取类的成员变量
从类中获取成员变量的方法
Class提供了从类中获取成员变量的方法 | 说明 |
public Field[] getFields() | 获取类全部的成员变量(只能获取public修饰的),使用较少 |
public Field[] getDeclaredFields() | 获取类的全部成员变量(只要存在就能拿到) |
public Field getField(String name) | 获取类的某个成员变量(只能获取public修饰的) |
public Field getDeclaredField(String name) | 获取类的某个成员变量(只要存在就能获取) |
获取到成员变量的作用
获取到成员变量的作用是赋值、取值
方法 | 说明 |
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 取值 |
public void setAccessible(boolean flag) | 设置为ture,表示禁止检查访问控制 |
public class Dog {
private String name;
private int age;
public static int o;
public static final String C = "狗狗";
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void Test3_Field() throws NoSuchFieldException {
//获取类的成员变量
//得到类的Class对象
Class dog = Dog.class;
//public Field[] getFields() 获取类全部的成员变量(只能获取public修饰的)
Field[] fields = dog.getFields();
for(Field f : fields){
System.out.println(f.getName() + "---->" + f.getType());
}
System.out.println("-------------------------------------");
//public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
Field[] fields1 = dog.getDeclaredFields();
for(Field f : fields1){
System.out.println(f.getName() + "---->" + f.getType());
}
System.out.println("-------------------------------------");
//public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的)
Field field = dog.getField("o");
System.out.println(field.getName() + "---->" + field.getType());
Field field2 = dog.getField("C");
System.out.println(field2.getName() + "---->" + field2.getType());
System.out.println("-------------------------------------");
//public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能获取)
Field field3 = dog.getDeclaredField("name");
System.out.println(field3.getName() + "---->" + field3.getType());
Field field4 = dog.getDeclaredField("age");
System.out.println(field4.getName() + "---->" + field4.getType());
System.out.println("===================================");
//void set(Object obj, Object value) 赋值
Dog dog1 = new Dog();
//field3->name 为私有 赋值会抛异常 需要 void setAccessible(boolean flag) 设置为ture,表示禁止检查访问控制
//public void setAccessible(boolean flag) 设置为ture,表示禁止检查访问控制
field3.setAccessible(true);
field3.set(dog1, "拉布拉多");
System.out.println(dog1);
//Object get(Object obj) 取值
//field3->name
String name = (String) field3.get(dog1);
System.out.println(name);
}
五. 获取类的成员方法
从类中获取成员方法
Class提供了从类中获取成员方法 | 说明 |
Method[] getMethods() | 获取类的全部成员方法(只能获取public 修饰的) 使用较少 |
Method[] getDeclaredMethods() | 获取类的全部成员方法(只要存在就能拿到) |
Method getMethod(String name, Class<?> parameterTypes) | 获取类的某个成员方法(只能获取public修饰的) |
Method getDeclaredMethod(String name, Class<?> parameterTypes) | 获取类的某个成员方法(只要存在就能拿到) |
获取成员方法的作用
获取成员方法的作用是执行该方法
Method提供的方法 | 说明 |
public Object invoke(Object obj, Object... args) | 执行某个对象的该方法 |
public void setAccessible(boolean flag) | 设置为ture,表示禁止检查访问控制 |
public class Dog {
private String name;
private int age;
public static int o;
public static final String C = "狗狗";
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String eat(String food) {
return "吃" + food + "吃的贼多";
}
public void run() {
System.out.println("跑的贼快");
}
private void sleep() {
System.out.println("睡得贼香");
}
}
@Test
public void testGetMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class d = Dog.class;
//Method[] getMethods() 获取类的全部成员方法(只能获取public 修饰的) 使用较少
Method[] methods = d.getMethods();
for(Method m : methods){
System.out.println(m.getName() + "-->" + m.getParameterTypes().length);
}
System.out.println("-------------------");
//Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到)
Method[] methods2 = d.getDeclaredMethods();
for(Method m : methods2){
System.out.println(m.getName() + "-->" + m.getParameterTypes().length);
}
System.out.println("-------------------");
//Method getMethod(String name, Class<?> parameterTypes) 获取类的某个成员方法(只能获取public修饰的)
Method method = d.getMethod("eat", String.class);
System.out.println(method.getName() + "-->" + method.getReturnType());
//Method getDeclaredMethod(String name, Class<?> parameterTypes) 获取类的某个成员方法(只要存在就能拿到)
Method method2 = d.getDeclaredMethod("sleep");
System.out.println(method2.getName() + "-->" + method2.getReturnType());
System.out.println("====================");
//public Object invoke(Object obj, Object... args) 执行某个对象的该方法
Dog dog = new Dog();
//method为 public 可直接调用
String s = (String) method.invoke(dog, "王中王");
System.out.println(s);
//method2->sleep为private 直接执行会报错 需要 void setAccessible(boolean flag) 设置为ture,表示禁止检查访问控制
//public void setAccessible(boolean flag) 设置为ture,表示禁止检查访问控制
method2.setAccessible(true);
method2.invoke(dog);
}
六. 反射的作用、应用场景
作用
1. 基本作用:可以得到一个类的全部成分然后进行操作。
2. 可以破坏封装性
3. 最重要的用途:适合做Java框架,主流的框架都会基于反射设计出一些通用的功能
简易版框架
实现步骤:
1. 定义一个方法,可以接收任意对象
2. 没收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
3. 变量成员变量,然后提取成员变量在该对象中的具体值
4. 把成员变量名和值写到文件中
public class Student {
private String name;
private int age;
private String gender;
private String grade;
public Student() {
}
public Student(String name, int age, String gender, String grade) {
this.name = name;
this.age = age;
this.gender = gender;
this.grade = grade;
}
}
public class Teacher {
private String name;
private int age;
private String subject;
public Teacher() {
}
public Teacher(String name, int age, String subject) {
this.name = name;
this.age = age;
this.subject = subject;
}
}
@Test
public void testA() throws Exception {
Student s1 = new Student("卡莎", 18, "女", "99.8");
Teacher teacher = new Teacher("张飞", 25, "语文");
ObjectFrame.saveObject(s1);
ObjectFrame.saveObject(teacher);
}