跳至主要內容

反射

Java反射Java反射大约 5 分钟约 1515 字全民制作人ikun

代理相关

为什么需要代理?

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

代理长什么样子?

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

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

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

代码演示:

  1. BigStar.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接口
public interface Star {
    //把需要被代理的方法定义在接口中
    String sing(String name);

    void dance();

}
  1. 代理工具

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. 测试类
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);
    }
}

反射

什么是反射?

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

获取反射三种方式

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

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:

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:

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:

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();

    }
}

学生类:

public class Student {
    private String name;
    private int age;
    private char gender;
    private double height;
    private String hobby;
}

教师类:

public class Teacher {
    private String name;
    private double salary;
}

上次编辑于:
贡献者: yunfeidog