目录
一.反射的简单解释与获取字节码文件对象
二.获取构造方法对象Constructor
三.反射获取字节码文件中的成员变量Field
四.反射获取字节码文件中的成员方法:Method
五.反射练习:保存信息
六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法
七.动态代理
一.反射的简单解释与获取字节码文件对象
反射:允许对封装类的成员变量、构造方法、成员方法获取出来然后进行操作,或者获取到如修饰符,名字等更加详细的信息 没有反射怎么拿?使用IO流!但是比较麻烦,这里就用反射咯1.获取Class的有哪三种方式? 1.Class.forName("全类名") 2.类名.class 3.对象.getClass() 对应三个不同的阶段 1.源代码:编译时期 2.加载阶段:在内存当中的时候 3.运行阶段:已经有对象了 2.这三种方法获取的是什么对象?
public class Demo351 {
public static void main(String[] args) throws ClassNotFoundException {
System.out.println("(1)获取Class的第一种方式:需要传入全类名的字符串:包含包名,最为常用");
System.out.println("IDEA中获取:选择类名,然后右键选择copy_Reference");
Class<?> class1 = Class.forName("Day35_Reflect_DynamicAgent.Demo351");
System.out.println(class1);
System.out.println("(2)获取Class的第二种方式,通过类名调用");
System.out.println("第二种则是多用于作为参数作为传递:比如当作锁");
Class<?> class2 = Demo351.class;
System.out.println("(3)获取Class的第三种方式,通过对象调用,也是获取的字节码文件");
//已经有对象的时候才可以使用
Class<?> class3 = new Student().getClass();
System.out.print("2.前两个类对象都是获取的字节码文件,是同一个对象:");
System.out.println(class2==class1);
}
}
学生类JavaBean,下面案例都是使用的此学生类
//四个构造方法:两个是私有的
//有个成员方法抛出了异常
public class Student {
private String name;
private int age;
public Student() {
}
private Student(String name) {
this.name = name;
}
private Student(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) throws Exception{
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
二.获取构造方法对象Constructor
从字节码文件里面获取数据对象的内容:本类测试获取构造方法对象Constructor 1.使用什么方法获取所有公共构造方法呢? 2.使用什么方法获取所有构造方法呢(包括私有)? 3.获取单个构造方法时传入的参数应该是? 4.如何获取构造方法内的权限修饰符? 5.如何读取方法中的参数? 6.如何使用私有构造方法创建变量?
public class Demo352 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字节码文件对象
Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");
System.out.println("1.使getConstructors获取构造方法,获取所有公共构造方法");
Constructor<?>[] constructors = studentClass.getConstructors();
for (Constructor<?> constructor : constructors) System.out.println(constructor);
System.out.println("2.获取所有构造方法(Declared:公开声明的)");
constructors = studentClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) System.out.println(constructor);
System.out.println("3.获取单个构造方法:指定构造方法可以传递参数:数据类型的字节码文件,基本数据类型也要传.class字节码文件");
Constructor<?> constructor = studentClass.getConstructor();
System.out.println(constructor);
constructor = studentClass.getConstructor(String.class,int.class);
System.out.println(constructor);
constructor = studentClass.getDeclaredConstructor(int.class);
System.out.println(constructor);
//获取构造方法里面的内容
System.out.println("4.使用getModifier方法读取权限修饰符:内容是2的整数倍(和底层运算效率有关,左右移就能改变)");
//有什么用呢?写IDEA源码有用,提示能够直接看到能传上面参数
System.out.println(constructor.getModifiers());
System.out.println("5.使用getParameters方法读取有哪些参数");
Parameter[] parameters = constructor.getParameters();
for (Parameter parameter : parameters) System.out.println(parameter);
System.out.println("6.使用构造方法创建对象:私有方法不能够创建对象,需要临时取消权限校验(暴力反射)");
System.out.println("首先把构造方法调用setAccessible方法,传入true为参数");
constructor.setAccessible(true);
System.out.println("再使用构造方法的newInstance方法构造其对象");
Student student = (Student) constructor.newInstance(23);
System.out.println(student);
}
}
三.反射获取字节码文件中的成员变量Field
反射获取字节码文件中的成员变量Field 1.获取单个变量需要传入的参数? 2.如何获取变量名? 3.如何获取变量类型? 4.如何获取对象中的变量的值? 5.如何修改对象中变量的值?
public class Demo353 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//获取Field也是一样的方法
Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");
Field[] fields = studentClass.getDeclaredFields();
for (Field field : fields) System.out.println(field);
System.out.println("1.获取单个成员变量:传入变量名字符串");
Field field = studentClass.getDeclaredField("age");
//获取成员变量信息
System.out.println(field.getModifiers());
System.out.println("2.使用getName方法获取变量名");
System.out.println(field.getName());
System.out.println("3.使用getType方法获取变量类型");
Class<?> type = field.getType();
System.out.println(type);
System.out.println("4.使用get方法传入某对象,获取这个成员变量在该对象中的值,同样也需要取消权限校验");
field.setAccessible(true);
Student student = new Student("zhangsan", 123);
Object age = field.get(student);
System.out.println(age);
System.out.println("5.使用set方法,传入某对象与修改的值,对该对象中的成员变量修改");
field.set(student,1234);
System.out.println(student);
}
}
四.反射获取字节码文件中的成员方法:Method
反射获取字节码文件中的成员方法:Method 1.使用getMethods方法与getDeclaredMethods方法有什么区别? 2.如何获取单个方法,传入的参数是? 3.如何返回方法抛出的异常? 4.如何使用method对某对象调用方法?传入的参数与返回的参数有什么特点?
public class Demo354 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");
Method[] methods = studentClass.getMethods();
System.out.println("1.使用getMethods方法同时也有继承与Object中的方法");
for (Method method : methods)System.out.println(method);
methods = studentClass.getDeclaredMethods();
System.out.println("获取所有方法的时候不会包含继承下来的方法");
for (Method method : methods)System.out.println(method);
System.out.println("2.通过名字和形参获取一个方法,可以不加形参");
Method method = studentClass.getMethod("setName",String.class);
System.out.println(method);
//修饰符,名字,参数
System.out.println(method.getModifiers());
System.out.println(method.getName());
for (Parameter parameter : method.getParameters())System.out.println(parameter);
System.out.println("3.使用getExceptionTypes返回方法抛出的异常数组");
System.out.println(Arrays.toString(method.getExceptionTypes()));
System.out.println("4.调用invoke(调用)方法,第一个参数传入对象,第二个参数没有就不写,方法没有返回也可以不写");
Student student = new Student();
method.invoke(student,"zhangsan");
System.out.println(student);
}
}
五.反射练习:保存信息
对于任意一个对象:把对象所有信息保存到文件当中,对于不同的对象都可以如此操作
public class Demo355 {
final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\message.properties";
public static void main(String[] args) throws IllegalAccessException, IOException {
Student student = new Student("zhansgan",123);
Properties properties =new Properties();
Class<?> studentClass = student.getClass();
//获取字节码文件中的所有成员变量
Field[] fields = studentClass.getDeclaredFields();
for (Field field : fields) {
//设置取消检验
field.setAccessible(true);
//获取变量名
String name = field.getName();
//获取对象中的该变量
Object o = field.get(student);
properties.put(name,o.toString());
}
properties.store(new FileWriter(FILE_STR),"addStudent");
}
}
六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法
public class Demo356 {
final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\prop.properties";
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Properties properties = new Properties();
properties.load(new FileReader(FILE_STR));
//获取字节码文件
Class<?> aClass = Class.forName((properties.get("classname").toString()));
//获取构造方法,创建对象
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();
//获取方法名并调用
Method method = aClass.getMethod(properties.get("method").toString());
System.out.println(method.invoke(o));
}
}
七.动态代理
动态代理:不修改原有的代码,又需要增加额外功能 为了程序的健壮性,不改变原有代码的功能,使用动态代理完成一些额外的事情 想要找某个核心人物做事情,需要先找它的代理人去说要做的事情,代理人里面也要有核心任务的方法如何确定需要代理的方法呢? 为了确定需要代理的方法,需要让核心人物与代理人都实现某一个接口
需要代理的类
public class BigStar implements Star {
private String name;
public BigStar() {}
public BigStar(String name) {
this.name = name;
}
@Override
public String sing(String name){
System.out.println(this.name+"正在唱:"+name);
return "谢谢";
}
@Override
public void dance(){
System.out.println("跳舞");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "BigStar{" +
"name='" + name + '\'' +
'}';
}
}
需要代理的方法的接口
public interface Star {
String sing(String name);
void dance();
}
代理工具类 :用来创建代理对象
public class ProxyUtil {
public static Star createProxy(BigStar bigStar) {
System.out.println("""
1.创建静态方法返回一个代理人(类型为BigStar实现的结构)
方法作用:给明星对象创建一个代理
形参:被代理的明星对象
返回一个接口,也是返回代理对象
""");
System.out.println("2.使用Proxy的newProxyInstance方法创建代理人对象,传入三个参数");
System.out.println("""
参数一:指定类加载器加载生成的代理类:找到谁加载了这个类
参数二:指定接口数组,用于指定代理能代理哪些方法
参数三:指定代理要干什么事情,在这个参数需要的对象需要实现的方法参数有三个
参数一:代理的对象,暂时用不到
参数二:要运行的方法
参数三:调用方法的时候需要传递的实参
""");
Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),
new Class[]{Star.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
参数一:代理的对象,暂时用不到
参数二:要运行的方法
参数三:调用方法的时候需要传递的实参
*/
if ("sing".equals(method.getName()))
System.out.println("代理人:准备话筒");
else if ("dance".equals(method.getName()))
System.out.println("代理人:准备场地");
//返回运行结果
return method.invoke(bigStar, args);
}
}
);
return star;
}
}
测试类
public class Demo361 {
public static void main(String[] args) {
//创建代理人
Star proxy = ProxyUtil.createProxy(new BigStar("mona"));
//使用代理人去调用方法
System.out.println(proxy.sing("偶像宣言"));
proxy.dance();
}
}