反射
(使编写的代码,更灵活,更高效)
学习目标
理解反射是什么,能做什么
能够正确使用反射技术获取类的成员并使用
一、基本概念
反射
在程序运行中分析类的一种能力;
(源文件(.java)—编译—》字节码文件(.class)——》运行(obj.method())
反过来即为反射。
功能
1、分析类
加载并初始化一个类;
查看类的所有的属性和方法;
2、查看并使用对象
查看一个对象的所有属性和方法;
使用对象的任意属性和方法;
应用场景
1、构建通用的工具;
2、搭建具有高度灵活性和扩展性的系统框架;
类加载器(ClassLoader)
负责将类的字节码文件(.class)加载到内存中,并生成对应的Class对象;
Class对象
java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件;
类加载的时机
1、创建类的实例;
Student stu = new Student();
2、访问类的静态成员
Calendar.getInstance();
3、初始化类的子类
class User extends Person{}
User user = new User;//先加载父类字节码文件,然后加载子类的字节码文件
4、反射方式创建类的Class对象
Class clazz = Class.forName(“类的正名”); //正名:包名+类名
获取Class对象的三种方式
1、Object类的getClass()方法
Class clazz = 对象名.getClass();
2、类的静态属性
Class clazz = 类名.class;
3、Class类的静态方法
Class clazz = Class.forName(“类的正名”); //正名:包名+类名
注意:一个源文件(.java文件)对应一个字节码文件对象(.class)
代码学习
package demo;
/**
* @author: @橘子先森
* @create: 2020-11-11 23:28
**/
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//需求:获取Class对象
//方式一、Object类的getClass()方法
Student student = new Student();
Class clazz1 = student.getClass();
//方式二、类的静态属性
Class clazz2 = Student.class;
//方式三、Class类的静态方法
Class clazz3 = Class.forName("demo.Student"); //正名:包名+类名
}
}
二、反射方式获取构造方法并使用
Constructor< T >对象
构造器对象,属于java.base模块,java.lang.reflect包
通过Class对象获取构造器对象
1、getConstructor(Class<?>… parameterTypes)
返回一个Constructor对象,仅公共构造函数Class<?>… :可变参数,代表Class类型的数组,?:通配符,代表不确定的任意类型;
2、getDeclaredConstructor(Class<?>… parameterTypes)
返回一个Constructor对象,可获取私有构造函数;
3、getConstructors)
返回此类所有(不含私有)构造函数的数组;
Constructor的常用方法
1、String getName()
返回构造函数名;
2、T newInstance(Object… initargs)
使用此构造函数和指定参数创建并初始化对象;
代码学习
package demo;
/**
* @author: @橘子先森
* @create: 2020-11-11 23:30
**/
public class Student {
//公共的无参构造
public Student() {
}
//公共的带参构造
public Student(String name) {
System.out.println("输入name值" + name);
}
//私有的带参构造
private Student(int age) {
System.out.println("输入age值" + age);
}
}
package demo;
import java.lang.reflect.Constructor;
/**
* @author: @橘子先森
* @create: 2020-11-11 23:58
**/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//需求:通过反射方式创建:Student类型的对象
//1、获取Student类的字节码文件对象
Class clazz1 = Class.forName("demo.Student");
//2、根据第一获取的字节码文件对象,获取指定的构造器对象
/*//2.1 获取公共的无参构造
Constructor constructor1 = clazz1.getConstructor();
System.out.println(constructor1);
//2.2 获取公共的无参构造
Constructor constructor2 = clazz1.getConstructor(String.class);
System.out.println(constructor2);
//2.3 获取私有的带参构造
Constructor constructor3 = clazz1.getDeclaredConstructor(int.class);
System.out.println(constructor3);
System.out.println("——————————————————————————————————————————");
//2.4 获取Student类的所有公共构造函数
Constructor[] cons = clazz1.getConstructors();
//遍历数组
for (Constructor con : cons) {
System.out.println(con);
}*/
//2.2 获取公共的无参构造————演示
Constructor constructor2 = clazz1.getConstructor(String.class);
System.out.println(constructor2);
//获取构造器名字
String name = constructor2.getName();
System.out.println(name);
//3、根据构造器对象和参数,创建对应的Student对象
//Object 张三 = constructor2.newInstance("张三"); //需要向下转型Student类,强转
Student student = (Student) constructor2.newInstance("张三");
//4、打印结果
System.out.println(student);
}
}
三、反射方式获取成员方法并使用
Method对象
方法对象,属于java.base模块,java.lang.reflect包;
通过Class对象获取方法
1、getMethod(String name, Class<?>… parameterTypes)
返回一个Method对象,仅公共成员方法;
name :方法名;
parameterTypes :方法的参数列表;
2、getDeclaredMethod(String, Class<?>.….)
返回一个Method对象,可获取私有成员方法;
3、getMethods()
返回此类所有(不含私有)方法的数组;
setAccessible(true)
开启暴力反射;
Method的常用方法
1、String getName()
返回方法名;
2、Object invoke(Object obj,Object…args)
在指定对象上调用此方法,参数为args;
代码学习
package demo;
/**
* @author: @橘子先森
* @create: 2020-11-11 23:30
**/
public class Student {
public static void show1() {
System.out.println("公共的空参方法");
}
public static void show2(int a) {
System.out.println("公共的带参方法,a" + a);
}
private static int show3(int a, int b) {
System.out.println("私有的带参方法");
return a + b;
}
}
import demo.Student;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @author: @橘子先森
* @create: 2020-11-12 11:05
**/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//通过反射获取Student类中的成员方法并调用
//1、获取Student类的字节码文件对象
Class clazz = Class.forName("demo.Student");
//2、获取该类的构造器对象,然后创建Student类的对象
Constructor con = clazz.getConstructor();
//Object o = con.newInstance(); //需要向下转型成Student类
Student stu = (Student)con.newInstance();
//System.out.println(stu);
//3、获取该类的成员方法对象,然后调用此方法
//3.1 调用公共的无参方法
Method method1 = clazz.getMethod("show1");
//打印方法对象
System.out.println(method1);
//打印方法名
System.out.println(method1.getName());
//调用方法
method1.invoke(stu);
System.out.println("————————————————————————————");
//3.2 调用公共的带参方法
Method method2 = clazz.getMethod("show2", int.class);
//打印方法对象
System.out.println(method2);
//打印方法名
System.out.println(method2.getName());
//调用方法
method2.invoke(stu,10);
System.out.println("————————————————————————————");
//3.3 调用私有的带参方法
Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
//开启暴力反射
method3.setAccessible(true);
//调用此方法
int sum = (int)method3.invoke(stu,19,21);
System.out.println(sum);
System.out.println("————————————————————————————");
//3.4 获取Student类中所有的成员方法
Method[] methods = clazz.getMethods();
//遍历
for (Method method : methods) {
System.out.println(method); //因为Student类默认继承Object类,所以也会打印继承的
}
}
}
四、反射方式获取成员变量并使用
filed对象
域(属性,成员变量)对象,属于java.base模块,java.lang.reflect包;
通过Class对象获取属性
1、getField(String name)
返回一个Field对象,仅公共属性;
name: 属性名;
2、getDeclaredField(String name)
返回一个Filed对象,可获取私有的;
3、getDeclaredFields()
返回此类所有(含私有)属性的数组;
Filed类的常用方法
1、void set(Object obj,Object value)
设置obj对象的指定属性为value;
2、viod setAccessible(boolean flag) //暴力反射
将此属性的可访问性设置为指定布尔值
代码学习
package demo;
/**
* @author: @橘子先森
* @create: 2020-11-11 23:30
**/
public class Student {
public String name;
private int age;
//用来打印对象的属性值
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @author: @橘子先森
* @create: 2020-11-12 11:50
**/
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
//需求:通过反射获取成员变量并使用
//1、获取Student类的字节码文件对象
Class clazz = Class.forName("demo.Student");
//2、通过字节码文件对象获取构造器对象,然后创建学生类对象
/*Constructor con = clazz.getConstructor();
Student student = (Student)con.newInstance();*/
Student stu = (Student)clazz.getConstructor().newInstance(); //链式编程,当一个方法返回值还是一个对象时
//3、设置学生对象的各个属性值
//3.1 设置名字 公有
Field name = clazz.getField("name");
name.set(stu,"张三");
//3.2 设置年龄 私有
Field age = clazz.getDeclaredField("age");
//开启暴力反射
age.setAccessible(true);
age.set(stu,12);
//4、打印学生对象
System.out.println(stu);
}
}