Java基础-反射

代理相关

为什么需要代理?

代理可以无侵入式的对方法进行增强,而不需要修改原始方法的代码,这样就可以在不修改原始方法的情况下,对方法进行增强。

代理长什么样子?

代理里面就是对象要被代理的方法

Java通过什么方式来保证代理的样子?

通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法

代码演示:

  1. BigStar.java
java 复制代码
public class BigStar implements Star {
    private String name;

    @Override
    public String sing(String name) {
        System.out.println(this.name + "正在唱" + name);
        return name;
    }

    @Override
    public void dance() {
        System.out.println(this.name + "正在跳舞");
    }
    //...
}
  1. Star接口
java 复制代码
public interface Star {
    //把需要被代理的方法定义在接口中
    String sing(String name);

    void dance();

}
  1. 代理工具
java 复制代码
public class ProxyUtil {
    /**
     * 作用:给一个明星对象创建代理
     * 形参:被代理的明星对象
     * 返回值:给明星创建的代理
     * <p>
     * 需求:外面的人需要大明星唱一首歌
     */
    public static Star createProxy(BigStar bigStar) {
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(), //参数一:类加载器
                new Class[]{Star.class}, //参数二:被代理类的所有接口
                //参数三:代理对象的调用处理程序
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, 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;
    }
}
  1. 测试类
java 复制代码
public class Test {
    public static void main(String[] args) {
        BigStar star = new BigStar("蔡徐坤");
        Star proxy = ProxyUtil.createProxy(star);
        String result = proxy.sing("只因你太美");
        System.out.println(result);
    }
}

反射

什么是反射?

反射允许对成员变量,成员方法和构造方法的信息进行编程访问

获取反射三种方式

java 复制代码
public class Test {
    public static void main(String[] args) throws Exception {
        //第一种方式:
        //最为常用的方式,通过类的全路径,获取Class对象
        Class clazz = Class.forName("com.cxk.fanshe.Student");

        //第二种方式,更多的是当作参数传递
        Class clazz2 = Student.class;

        //第三种方式
        //当我们已经有了这个类的对象,才可以使用
        Student student = new Student();
        Class clazz3 = student.getClass();
    }
}

反射获取构造方法

Declared表示私有

方法名 说明
Constructor<?>[] getConstructors() 获得所有的构造(只能public修饰)
Constructor<?>[] getDeclaredConstructors() 获得所有的构造(包含private修饰)
Constructor getConstructor(Class<?>... parameterTypes) 获取指定构造(只能public修饰)
Constructor getDeclaredConstructor(Class<?>... parameterTypes) 获取指定构造(包含private修饰)

Demo

java 复制代码
public class Test {
    public static void main(String[] args) throws Exception {
        //1.获取class字节码文件对象
        Class<?> clazz = Class.forName("com.cxk.fanshe.Student");
        //2.1获取所有的构造方法
        Constructor[] con1 = clazz.getDeclaredConstructors();
        for (Constructor constructor : con1) System.out.println(constructor);

        //2.2获取指定的构造方法
        Constructor con2 = clazz.getDeclaredConstructor(); //空参
        Constructor con3 = clazz.getDeclaredConstructor(String.class, Integer.class); //有参

        int modifiers = con3.getModifiers();        //获取权限修饰符
        Parameter[] parameters = con3.getParameters();//获取参数列表

        con3.setAccessible(true);//暴力反射 无视权限修饰符 这样就可以访问私有构造方法了
        Student cxk =(Student) con3.newInstance("cxk", 23);//创建对象
    }
}

获取成员变量

方法名 说明
Field[] getFields() 返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
Field getField(String name) 返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到

Demo:

java 复制代码
public class Test {
    public static void main(String[] args) throws Exception {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("com.cxk.fanshe.Student");

        Field[] fields = clazz.getDeclaredFields();//获取成员变量 所有的
        Field age = clazz.getDeclaredField("age");//获取单个的
        int modifiers = age.getModifiers();//获取权限修饰符
        Class type = age.getType();//获取数据类型
        String name = age.getName();//获取变量名
        Student cxk = new Student("cxk", 30);

        age.setAccessible(true);//暴力反射
        Integer value =(Integer) age.get(cxk);
        System.out.println(value);
        age.set(cxk, 18);//修改已记录的值
        System.out.println(cxk);
    }
}

获取成员方法

方法名 说明
Method[] getMethods() 返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象,存在就能拿到

Demo:

java 复制代码
public class Test {
    public static void main(String[] args) throws Exception {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("com.cxk.fanshe.Student");

        Method[] methods1 = clazz.getMethods(); //获取所有的方法(包括父类)
        Method[] methods = clazz.getDeclaredMethods();//获取所有的方法(不能获取父类)

        Method eat = clazz.getMethod("eat", String.class);//获取单一方法
        int modifiers = eat.getModifiers();//获取方法的修饰符
        String name = eat.getName();//获取方法的名称
        int parameterCount = eat.getParameterCount();//获取方法的参数个数
        Class returnType = eat.getReturnType();//获取方法的返回值类型
        Parameter[] parameters = eat.getParameters();//获取方法的参数列表
        Class[] parameterTypes = eat.getParameterTypes();//获取方法的参数类型列表

        Student cxk = new Student("cxk", 30);
        eat.setAccessible(true);//暴力反射 使私有方法可以被访问
        String apple =(String) eat.invoke(cxk, "apple");//执行方法
    }
}

利用反射保存对象信息

Demo:

java 复制代码
public class Test {
    public static void main(String[] args) throws  Exception {
    /*
        对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
    */
        Student s = new Student("小A",23,'女',167.5,"睡觉");
        Teacher t = new Teacher("播妞",10000);
        saveObject(s);
        saveObject(t);
    }

    //把对象里面所有的成员变量名和值保存到本地文件中
    public static void saveObject(Object obj) throws  Exception {
        //1.获取字节码文件的对象
        Class clazz = obj.getClass();
        //2. 创建IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("./a.txt"));
        //3. 获取所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            //获取成员变量的名字
            String name = field.getName();
            //获取成员变量的值
            Object value = field.get(obj);
            //写出数据
            bw.write(name + "=" + value);
            bw.newLine();
        }

        bw.close();

    }
}

学生类:

java 复制代码
public class Student {
    private String name;
    private int age;
    private char gender;
    private double height;
    private String hobby;
}

教师类:

java 复制代码
public class Teacher {
    private String name;
    private double salary;
}
相关推荐
沛沛老爹6 小时前
Web开发者突围AI战场:Agent Skills元工具性能优化实战指南——像优化Spring Boot一样提升AI吞吐量
java·开发语言·人工智能·spring boot·性能优化·架构·企业开发
Full Stack Developme7 小时前
Redis 实现主从同步
java·redis·spring
一只爱学习的小鱼儿7 小时前
在QT中使用饼状图进行数据分析
开发语言·qt·数据分析
yangminlei7 小时前
Spring Boot 响应式 WebFlux 从入门到精通
java·spring boot·后端
曹轲恒7 小时前
SpringBoot配置文件
java·spring boot
亓才孓7 小时前
[认识异常和错误]java
java·开发语言
码农水水7 小时前
中国电网Java面试被问:流批一体架构的实现和状态管理
java·c语言·开发语言·面试·职场和发展·架构·kafka
1***43807 小时前
C++跨平台开发的核心挑战线程管理等基础功能
开发语言·c++
做萤石二次开发的哈哈7 小时前
萤石开放平台 萤石可编程设备 | 设备脚本自定义开发
开发语言·python·萤石云·萤石·萤石开放平台