目录
一.反射的简单解释与获取字节码文件对象
二.获取构造方法对象Constructor
三.反射获取字节码文件中的成员变量Field
四.反射获取字节码文件中的成员方法:Method
五.反射练习:保存信息
六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法
七.动态代理
一.反射的简单解释与获取字节码文件对象
反射:允许对封装类的成员变量、构造方法、成员方法获取出来然后进行操作,或者获取到如修饰符,名字等更加详细的信息 没有反射怎么拿?使用IO流!但是比较麻烦,这里就用反射咯1.获取Class的有哪三种方式?1.Class.forName("全类名")2.类名.class3.对象.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;}@Overridepublic 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;}@Overridepublic String sing(String name){System.out.println(this.name+"正在唱:"+name);return "谢谢";}@Overridepublic void dance(){System.out.println("跳舞");}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic 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() {@Overridepublic 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();}
}