菜鸟之路Day22一一反射与动态代理
作者:blue
时间:2025.3.4
0.概述
内容学习自黑马程序员BV1yW4y1Y7Ms
1.什么是反射
反射允许对成员变量,成员方法和构造方法的信息进行编程访问
获取class对象 Class
构造方法 Constructor
字段(成员变量)Field
成员方法 Method
2.获取class对象的三种方式
public class myreflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/*
* 获取class对象的三种方式
* 1.Class.forName("全类名");
* 2.类名.class;
* 3.对象.getClass();
* */
//1.第一种方式
//全类名:包名+类名
//最为常用的
Class clazz1 = Class.forName("myreflect.Student");
//2.第二种方式
//一般更多的是当做参数进行传递
Class clazz2 = Student.class;
//3.第三种方式
//当我们已经有这个类的对象时,才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
}
}
AI 代码解读
3.反射获取构造方法
类中有四个构造方法
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;
}
AI 代码解读
对获取构造方法相关方法的实例
public class myReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
* Class类中用于获取构造方法的方法
* Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
* Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
* Constructor<?>getConstructor(Class<?>...parameterTypes):返回单个公共构造方法对象
* Constructor<?>getDeclaredConstructor(Class<?>...parameterTypes):返回单个构造方法对象
*
* Constructor类中用于创建对象的方法
* T newInstance(Object... initargs):根据指定的构造方法创建对象
* setAccessible(boolean flag):设置为true,表示取消访问检查
* */
//获取Class对象(Student类)
Class clazz = Class.forName("myreflect.Student");
/*
//返回所有公共构造方法对象的数组
Constructor[] cons1 = clazz.getConstructors();
for (Constructor constructor : cons1) {
System.out.println(cons1);
}
*/
/*
//返回所有构造方法对象的数组
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor constructor : cons2) {
System.out.println(constructor);
}
*/
//获取一个公共的空参构造
Constructor con1 = clazz.getConstructor();
System.out.println(con1);
//获取一个公共的参数为String的构造
Constructor con2 = clazz.getConstructor(String.class);
System.out.println(con2);
//获取一个私有的,带两个参数的构造
Constructor con3 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con3);
//获取构造方法的修饰符的状态码
int modifiers = con3.getModifiers();
System.out.println(modifiers);//con3是private的所以他的状态码是2
//获取构造方法的参数列表
Parameter[] parameters = con3.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//利用获取到的Class对象,来创建其对应的对象
//调用方法newInstance
//但是这里展现出反射的一个用法
//就是暴力反射
//可以临时取消权限校验,使用本来被私有化的构造方法来创建对象
con3.setAccessible(true);//临时取消权限校验
Student s = (Student) con3.newInstance("张三",18);
System.out.println(s);
}
}
AI 代码解读
4.反射获取成员变量
private String name;
private int age;
public String gender;
//总共有三个成员变量
AI 代码解读
对获取成员变量相关方法的实例
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/*
* Class类中用于获取成员变量的方法
* Field[] getFields():返回所有公共成员变量对象的数组
* Field[] getDeclaredFields():返回所有成员变量的数组
* Field getField(String name):返回单个公共成员变量对象
* Field getDeclaredField(String name):返回单个成员变量对象
*
* Field类中用于创建对象的方法
* void set(Object obj,Object value):赋值
* Object get(Object obj)获取值
* */
//获取Class(Student)对象
Class<?> clazz = Class.forName("myreflect.myreflectDemo3.Student");
//返回所有公共成员变量对象的数组
Field[] fields1 = clazz.getFields();
/*for (Field field : fields1) {
System.out.println(field);
}*/
//返回所有成员变量的数组
Field[] fields2 = clazz.getDeclaredFields();
/*for (Field field : fields2) {
System.out.println(field);
}*/
//返回单个 公共 成员变量对象
Field field = clazz.getField("gender");
//System.out.println(field);
//返回单个成员变量对象
Field field1 = clazz.getDeclaredField("name");
//System.out.println(field1);
//获取变量的权限修饰符
int modifiers = field1.getModifiers();
//System.out.println(modifiers);
//获取成员变量的数据类型
Class<?> type = field1.getType();
//System.out.println(type);
//获取或修改成员变量中的值
//可以通过暴力反射直接获取或修改
Student s = new Student("zhangsan",23,"男");
field1.setAccessible(true);////临时取消该变量的权限校验
String value = (String)field1.get(s);
System.out.println(value);
field1.set(s,"lisi");
System.out.println(s);
}
}
AI 代码解读
5.反射获取成员方法
类中有两个成员方法
private String eat(String something){
System.out.println("正在吃"+something);
return "nice";
}
//一个重载
public void eat(String something,int count) throws IOException,NullPointerException {
System.out.println("正在吃"+count+"个"+something);
}
AI 代码解读
对获取成员方法的实例
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
/*
* Class类中用于获取成员方法的方法
* Method[] getMethods():返回所有公共成员方法对象数组,包括继承的
* Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
* Method getMethod(String name,Class<?>...parameterTypes):返回单个公共成员方法对象
* Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回单个成员方法对象
* */
Class clazz = Class.forName("myreflect.myreflectDemo4.Student");
//返回所有公共成员方法对象数组,包括继承的
Method[] methods = clazz.getMethods();
/*for (Method method : methods) {
System.out.println(method);
}*/
//返回所有成员方法对象的数组,不包括继承的
Method[] methods1 = clazz.getDeclaredMethods();
/*for (Method method : methods1) {
System.out.println(method);
}*/
//返回单个 公共 成员方法对象
Method eat = clazz.getMethod("eat", String.class, int.class);
//System.out.println(eat);
//返回单个成员方法对象
Method eat_private = clazz.getDeclaredMethod("eat", String.class);
//System.out.println(eat_private);
//获取方法的修饰符
int modifiers = eat_private.getModifiers();
//System.out.println(modifiers);
//获取方法的名字
//System.out.println(eat_private.getName());
//获取方法的形参
Parameter[] parameters = eat_private.getParameters();
/*for (Parameter parameter : parameters) {
System.out.println(parameter);
}*/
//获取方法抛出的异常
Class<?>[] exceptionTypes = eat.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
/*
* Method类中用于创建对象的方法
* Object invoke(Object obj,Object... args):运行方法
* 参数一:用obj对象调用该方法
* 参数二:调用方法的传递的参数(如果没有就不写)
* 返回值:方法的返回值(如果没有就不写)
* */
Student stu = new Student("zhangsan",14,"男");
//暴力反射调用私有化方法
eat_private.setAccessible(true);
Object x = eat_private.invoke(stu, "牛肉");
System.out.println(x);
}
}
AI 代码解读
6.综合练习
反射的作用
①获取一个类里面所有的信息,获取到了之后,再执行其他业务逻辑
②结合配置文件,动态的创建对象并调用方法
6.1保存信息
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IOException {
Student stu = new Student("zhangsan",18,"男");
Teacher t = new Teacher("lisi","10000");
saveObject(t);
}
private static void saveObject(Object object) throws ClassNotFoundException, IllegalAccessException, IOException {
//获取Class对象
Class clazz = object.getClass();
//获取所有成员变量
Field[] declaredFields = clazz.getDeclaredFields();
BufferedWriter bw = new BufferedWriter(new FileWriter("src\\MyReflectTest\\TestOne\\a.txt"));
//遍历
for (Field declaredField : declaredFields) {
//暴力反射
declaredField.setAccessible(true);
//获取变量名与值
String name = declaredField.getName();
Object o = declaredField.get(object);
//写出数据
bw.write(name+"="+o);
bw.newLine();
}
//释放资源
bw.close();
}
}
AI 代码解读
6.2跟配置文件结合动态创建
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取配置文件中的信息
Properties properties = new Properties();
FileInputStream fis = new FileInputStream("src/MyReflectTest/TestTwo/a.properties");
properties.load(fis);
fis.close();
//System.out.println(properties);
//2.获取全类名和方法名
String className = (String)properties.get("className");
String Method = (String)properties.get("Method");
//3.利用反射创建对象并运行方法
Class clazz = Class.forName(className);
//获取构造方法
Constructor declaredConstructor = clazz.getDeclaredConstructor();
//创建对象
Object o = declaredConstructor.newInstance();
//获取成员方法并运行
java.lang.reflect.Method declaredMethod = clazz.getDeclaredMethod(Method);
declaredMethod.setAccessible(true);
declaredMethod.invoke(o);
}
}
AI 代码解读
6.3总结
1.反射的作用
①获取任意一个类中的所有信息
②结合配置文件动态创建对象
2.获得class字节码文件对象的三种方式
①Class.forName("全类名")
②类名.class
③对象.getclass();
3.如何获取构造方法,成员方法,成员变量
get:获取 set:设置
Constructor:构造方法 Parameter:参数
Field:成员变量 Modifiers:修饰符
Method:方法 Declared:私有的
7.动态代理
1.为什么需要代理?
代理可以无侵入式的给对象增强其他的功能
调用者 -> 代理 -> 对象
2.代理长什么样子?
代理里面就是对象要被代理的方法
3.Java通过什么来保证代理的样子?
通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法
Star接口
public interface Star {
public abstract String sing(String Singname);
public abstract void dance();
}
AI 代码解读
BigStar类
public class BigStar implements Star{
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
@Override
public String sing(String Singname) {
System.out.println(this.name+"正在唱"+Singname);
return "谢谢";
}
@Override
public void dance() {
System.out.println(this.name+"正在跳舞");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
AI 代码解读
代理
public class ProxyUtil {
public static Star createProxy(BigStar bigStar){
/*
* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 参数一:用于指定用哪个类加载器,去加载生成的代理类
* 参数二:指定接口,这些接口用于指定生成的代理长什么样子,也就是有哪些方法
* 参数三:用来指定生成的代理对象要干什么事情
* */
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 {
/*
* 参数一:代理的对象
* 参数二:要运行的方法 sing
* 参数三:调用sing方法时,传递的实参
* */
if("sing".equals(method.getName())){
System.out.println("准备话筒,收钱");
}else if("dance".equals(method.getName())){
System.out.println("准备场地,收钱");
}
//让bigStar执行相关方法
//依靠反射实现
return method.invoke(bigStar,args);
}
}
);
return star;
}
}
AI 代码解读
测试类
public class Test {
public static void main(String[] args) {
//获取代理对象
BigStar star = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(star);
//调用唱歌方法
String s = proxy.sing("只因你太美");
System.out.println(s);
}
}
AI 代码解读