Java基础--反射和动态代理

.1 反射

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

作用:

        获取任何一个类中的所有信息

        结合配置文件动态创建对象

 .2 获取class字节码文件对象的三种方式

一、格式:Class.forName("全类名");

源代码阶段

二、格式:类名.class

加载阶段 -- 内存中

三、格式:对象.getClass();

运行阶段 -- 内存中 

//反射
public class ReflectDemo1 {
    //获取class对象 字节码文件  字节码文件是唯一的 可以用来做锁对象
    public static void main(String[] args) throws ClassNotFoundException {

        //第一种方式  最为常用
        //全类名:包名+类名      Class.forName("全类名")
        Class class1 = Class.forName("ReflectDemo.Student");
        System.out.println(class1);

        //第二种方式  一般更多的时候当作参数传递
        // 类名.class
        Class class2 = Student.class;
        System.out.println(class2);

        ///第三种方式  当我们已经有了这个类的对象时才可以使用
        //对象.getClass()
        Student s = new Student();
        Class class3 = s.getClass();
        System.out.println(class3);

        //三种方式获得的class对象相同  这里比较的是地址值
        System.out.println(class1 == class2);//true
        System.out.println(class2 == class3);//true
    }
}

.3 获取构造、成员方法、成员变量

get:获取                                        set:设置

Constructor:构造方法                    Parameter:参数

Field:成员变量                               Modifier:修饰符

Method:方法                                  Declared:私有的

.3.1 获取构造方法

可以获取构造方法的修饰符,获取名称,获取形参,创建对象

//反射获取构造方法
public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //构造方法需要通过字节码文件的对象
        //写class会报错
        Class class1 = Class.forName("ReflectDemo.Student");

        //获取所有公共的构造方法并存放到数组当中
        Constructor[] con1 = class1.getConstructors();
        for (Constructor con : con1) {
            System.out.println(con);
        }
        System.out.println("-----------------------------------");
        //Declared权限
        //获取其所有的构造方法并存放到数组当中
        Constructor[] con2 = class1.getDeclaredConstructors();
        for (Constructor con : con2) {
            System.out.println(con);
        }
        System.out.println("-----------------------------------");
        //获取一个公共构造方法
        //没传参数就是获取空参的
        Constructor con3 = class1.getConstructor();
        System.out.println(con3);
        System.out.println("-----------------------------------");
        //传对应类型的字节码文件
        Constructor con4 = class1.getConstructor(String.class);
        System.out.println(con4);
        System.out.println("-----------------------------------");

        //获取所有的其中一个构造方法 可以获取私有的构造方法
        // 这个只能是让你看到了这个私有构造方法的信息,
        // 往里面还需要暴力反射 con5.setAccessible(true)
        Constructor con5 = class1.getDeclaredConstructor(String.class, Integer.class);
        System.out.println(con5);
        System.out.println("-----------------------------------");

        //获取了构造方法之后的用途

        //1.获取这个构造方法的权限修饰符
        int modifiers = con5.getModifiers();
        System.out.println(modifiers);//public :1  private是2
        System.out.println("-----------------------------------");

        //获取构成方法的参数信息
        //Parameter:参数
        //con5.getParameterTypes() 返回这个构造方法的所有参数类型 String Integer
        //con5.getParameterCount() 获取参数的个数
        //获取这个构成方法的所有参数并放到数组中返回
        Parameter[] parameters = con5.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        System.out.println("-----------------------------------");

        //创建这个构造方法的对象 只能看不能赋值
        //临时取消权限校验可以赋值
        con5.setAccessible(true); //暴力反射
        Student stu = (Student)con5.newInstance("张三", 18);
        System.out.println(stu);
        System.out.println("-----------------------------------");
    }
}

.3.2 获取成员方法

获取成员方法的修饰符,名字,形参,返回值,抛出的异常,注解,运行方法

public class ReflectDemo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        //获取字节码文件的对象
        Class<?> class1 = Class.forName("ReflectDemo.Student");

        //获取所有公共的成员方法 并存到数组当中   包含父类的所有的公共方法
        Method[] methods = class1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-----------------------------------");

        //获取所有的成员方法  不能获取父类的
        Method[] declaredMethods = class1.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("-----------------------------------");

        //获取一个公共的成员方法  传入方法名字 方法的形参 空参不用传
        Method sleep = class1.getMethod("sleep");
        System.out.println(sleep);
        System.out.println("-----------------------------------");

        //获取一个成员方法
        Method eat = class1.getDeclaredMethod("eat", String.class);
        System.out.println(eat);
        System.out.println("-----------------------------------");

        //获取方法的修饰符
        int modifiers = eat.getModifiers();
        System.out.println(modifiers);
        System.out.println("-----------------------------------");

        //获取方法的名字
        String name = eat.getName();
        System.out.println(name);
        System.out.println("-----------------------------------");

        //获取方法的形参  还有参数类型参数个数等
        Parameter[] parameters = eat.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        System.out.println("-----------------------------------");

        //获取方法的异常
        Class<?>[] exceptionTypes = eat.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }
        System.out.println("-----------------------------------");

        //方法运行  运行获取出来的方法
        //参数一 用obj对象调用该方法
        //参数二 调用方法的传递的参数(如果没有就不写)
        //返回值 方法的返回值 如果没有就不写
        //获取方法的返回值
        //创建Student对象
        Student stu = new Student();
        //参数一 方法的调用者 参数二 调用时实际传递的参数
        eat.setAccessible(true);
        Object result = eat.invoke(stu, "汉堡包");//这里执行的方法体
        System.out.println(result);
        System.out.println("-----------------------------------");
    }
}

.3.3 获取成员变量

获取修饰符,名字,类型,赋值/获取值

//获取成员变量
public class ReflectDemo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

        //先获取字节码文件的对象
        Class<?> class1 = Class.forName("ReflectDemo.Student");

        //获取所有公共的成员变量并储存在数组当中
        Field[] fields1 = class1.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }
        System.out.println("-----------------------------------");

        //获取所有的成员变量并储存在数组当中
        Field[] fields2 = class1.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }
        System.out.println("-----------------------------------");

        //获取单个的公共的成员变量  根据变量名
        Field name = class1.getField("address");
        System.out.println(name);
        System.out.println("-----------------------------------");

        //获取单个的私有的成员变量  根据变量名
        Field privateName = class1.getDeclaredField("name");
        System.out.println(privateName);
        System.out.println("-----------------------------------");

        //用途

        //1.获取权限修饰符
        int modifiers = privateName.getModifiers();
        System.out.println(modifiers);
        System.out.println("-----------------------------------");

        //获取成员变量的名字
        String name1 = privateName.getName();
        System.out.println(name1);//name
        System.out.println("-----------------------------------");

        //获取成员变量的数据类型
        Class<?> type = privateName.getType();
        System.out.println(type);
        System.out.println("-----------------------------------");

        //获取成员变量记录的值 先创建类对象
        Student stu = new Student("zhangsan",13,"河北");
        //因为name是私有化的还需要暴力反射 临时取消权限
        privateName.setAccessible(true);
        String value = (String) privateName.get(stu);
        System.out.println(value);
        System.out.println("-----------------------------------");
        //修改对象里面的值
        //也需要暴力反射 上面已经对privateName暴力反射了
        privateName.set(stu,"lisi");
        System.out.println(stu);
    }
}

.4  动态代理

 代理可以无侵入式的给对象增强其他功能

        调用者--->代理 -----> 对象

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

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

实现动态代理

 java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法。

public interface Star {

    //我们可以把所有想要被代理的方法定义在接口当中

    //唱歌
    public abstract String sing(String name);

    //跳舞
    public abstract void dance();
}
对象里需要被代理的方法
//对象类实现接口
public class BigStar implements Star{
    @Override
    public String sing(String name) {
        System.out.println(this.name+"唱了"+name+"歌");
        return "谢谢";
    }

    @Override
    public void dance() {
        System.out.println(this.name+"跳了一段舞");
    }
}
//类的作用 创建一个代理
//不用实现接口,在Proxy.newProxyInstance参数里面指定接口
public class ProxyUtil {

    /*
    * 方法的作用:
    *        给一个明星的对象,创建一个代理
    * 形参:
    *      被代理的明星对象
    *
    * 返回值:
    *   给明星创建的代理
    *
    * */
    //代理也要实现Star这个接口的就设置成Star类型
    public static Star createProxy(BigStar bigStar){
        //java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法

        //参数一:用于指定用哪个类加载器,去加载生成的代理类
        //参数二 指定接口 这些接口用于指定生成的代理长什么样,也就是有哪些方法 (实现接口的.class文件)
        //参数三用来指定生成的代理对象要做什么事情
        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("准备场地,收钱");
                        }
                        //去找大明星开始准备
                        //调用大明星里面唱歌或者跳舞的方法 还可能有参数
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
}
public class Text {
    public static void main(String[] args){
        //获取代理人对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        //调用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);

        //调用跳舞的方法
        proxy.dance();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值