java day17 反射 & 注解 & 动态代理

目录

反射:

1.Class对象的获取:

2.反射获取类中构造器:

3.反射获取成员变量:

4.反射获取成员方法:

注解:

注解的定义:

元注解: 

注解的使用(重点):

注解的解析:

动态代理:


反射:

一种 加载类 并且操作类的成分(构造方法,成员变量,成员方法)的方式

可以操作一个不存在的类 是框架的灵魂

类执行的流程:

1.编写java源文件

2.编译源文件,产生.class字节码文件 

3.使用类加载器 把类加载到内存当中  在内存中会有哟个Class对象用于记录当前类的所有成分

1.Class对象的获取:

三种方法:1.Class.forName(全类名)  全类名为 包名.类名 

                  2.对象.getClass()

                  3.类名.class

 public static void main(String[] args) throws ClassNotFoundException {
        //1. Class.forName(String className): className: 包名.类名  |  全类名
        Class clazz = Class.forName("com.itheima.reflect.Student");
        System.out.println(clazz);


        //2. 对象.getClass(): 获取对象所属的类对象
        Student s1 = new Student();
        Class clazz2 = s1.getClass();//getClass来自于Object
        System.out.println(clazz2);

        //3. 类名.class: 获取某个类的类对象
        Class clazz3 = Student.class;
        System.out.println(clazz3);

        //3次获取到的Class对象是同一个, 一个类在一次程序运行过程中只加载一次!!,所以在方法区中只有对应的一个Class类对象
        System.out.println(clazz == clazz2);
        System.out.println(clazz2 == clazz3);
    }

2.反射获取类中构造器:

public static void main(String[] args) throws Exception {
        //1.获取字节码文件对象
        Class clazz = Class.forName("com.itheima.reflect.Student");
        //2.获取构造器对象  Constructor
        //获取所有被public修饰的构造方法
        Constructor[] cs = clazz.getConstructors();
        System.out.println(Arrays.toString(cs));

        //获取所有权限修饰的构造方法,无视权限修饰符
        Constructor[] cs2 = clazz.getDeclaredConstructors();
        System.out.println(Arrays.toString(cs2));

        //获取指定参数的构造方法, 被public修饰的
        Constructor c1 = clazz.getConstructor();
        System.out.println(c1);

        Constructor c2 = clazz.getConstructor(String.class, int.class);
        System.out.println(c2);

        //获取指定参数的构造方法, 无视权限修饰符
        Constructor c3 = clazz.getDeclaredConstructor(String.class);
        System.out.println(c3);

        //Constructor: newInstance(Object... args)
        Object obj = c2.newInstance("柳岩", 23);
        System.out.println(obj);

        Object obj2 = c1.newInstance();
        System.out.println(obj2);

        //设置私有可访问, 暴力反射
        //如过构造器为私有不让创建对象 可用暴力反射创建 (暴力反射, 忽略权限修饰符)
        c3.setAccessible(true);
        Object obj3 = c3.newInstance("龚玥菲");
        System.out.println(obj3);
    }

3.反射获取成员变量:

public static void main(String[] args)  throws Exception {
        //1.加载类,获取Class对象
        Class clazz = Class.forName("com.itheima.reflect.Student");
        //目标对象
        Object target = clazz.getConstructor().newInstance();

        //2.获取成员变量对象Filed
        //获取被public修饰的成员变量
        Field[] fs1 = clazz.getFields();
        System.out.println(Arrays.toString(fs1));

        //获取所有的成员变量,无视权限修饰符
        Field[] fs2 = clazz.getDeclaredFields();
        System.out.println(Arrays.toString(fs2));

        //根据名字获取指定的Filed对象,只能获取public修饰的
        Field ageField = clazz.getField("age");
        System.out.println(ageField);

        //根据名字获取指定的Filed对象,无视权限修饰符
        Field nameField = clazz.getDeclaredField("name");
        System.out.println(nameField);

        //set(Object obj, Object value) obj: 你要给哪个对象的该变量赋值, value: 赋的值
        ageField.set(target,23);
        //暴力反射
        nameField.setAccessible(true);
        nameField.set(target,"柳岩");

        //Object get(Object obj)  obj: 要获取哪个对象的该成员变量的值
        System.out.println(ageField.get(target));
        System.out.println(nameField.get(target));
    }

4.反射获取成员方法:

Method方法对象为静态方法时 invoke第一个参数传null

public static void main(String[] args)throws Exception {
        //1.加载类,获取Class对象
        Class clazz = Class.forName("com.itheima.reflect.Student");

        //目标对象
        Object target = clazz.getConstructor().newInstance();

        //2.获取方法对象, 获取当前类以及父类中的方法 获取被public修饰的
        Method[] ms1 = clazz.getMethods();
        System.out.println(Arrays.toString(ms1));

        //根据方法名和参数列表获取方法
        //getMethod(String name, Class<?>... parameterTypes) name:方法名, parameterTypes: 参数列表的类型
        Method methodMethod = clazz.getMethod("method", String.class);
        System.out.println(methodMethod);

        //执行方法
        //invoke(Object obj, Object... args) obj: 要执行那个对象的该方法, args: 调用方法时传递的参数
        methodMethod.invoke(target,"我爱柳岩一万年????");

    }

注解:

概念:是堆程序的一种特殊标识,给程序看的,程序可以通过这些标识,选择不同的执逻辑

注解本质是一个接口    枚举本质是一个类调用其静态常量

注解的定义:



元注解: 

 有两种元注解:

parameter方法参数

注解的使用(重点):

   格式:     @注解名(属性名=值,属性名=值)

注意:

        1.如果给数组赋值 ,数组里只有一个元素 {}可以省略 

        2.如果只给变量名为value的属性赋值  那么valve=可以胜略

        3.本质实现了一个接口的实现类对象

注解的解析:

核心思想:在哪个位置上使用的注解,需要找到该位置对应的反射现象(Class,Constructor,Field,Method)解析

 注解的定义:

@Target(ElementType.METHOD)//只能在方法上使用RequestMapping注解
@Retention(RetentionPolicy.RUNTIME)//标识该注解会保存在运行时阶段
public @interface RequestMapping {
    String value();//执行方法对应的字符串标识
}

注解的使用:

public class UserController {

    @RequestMapping("/addUser")//标识将来用户输入了/addUser后,执行addUser方法
    public void addUser() {
        System.out.println("添加用户...");
    }

    @RequestMapping("/deleteUser")
    public void deleteUser() {
        System.out.println("删除用户...");
    }

    @RequestMapping("/updateUser")
    public void updateUser() {
        System.out.println("修改用户...");
    }

    @RequestMapping("/seleteUser")
    public void selectUser() {
        System.out.println("查询用户...");
    }


    public void login() {
        System.out.println("登录...");
    }

    @RequestMapping("/show")
    public void show() {
        System.out.println("show......");
    }

}

注解的解析:

public class SpringMvc {
    public static void main(String[] args) throws Exception {
        //0.创建一个Map集合,用于记录录入的字符串和对应的Method对象的对应关系
        Map<String, Method> map = new HashMap<>();
        //1.加载UserController类,得到Class字节码文件对象
        Class clazz = UserController.class;
        //2.获取空参构造器,并创建目标对象
        Object target = clazz.getConstructor().newInstance();
        //3.借助于Class字节码文件对象,获取到所有的方法 Method[] getMethods(), 可以获取到父类中的方法
        Method[] ms = clazz.getMethods();
        //4.遍历Method[] 数组,得到每一个Method(某一个方法)
        //5.判断Method对应的方法上有没有@RequestMapping注解
        Arrays.stream(ms).filter(m -> m.isAnnotationPresent(RequestMapping.class)).forEach(m->{
            //6.如果有, 获取@RequestMapping注解中的value属性值
            RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class);
            String value = rm.value();// /addUser
            //7.把value属性值和method对象存储到Map集合中
            map.put(value,m);
        });
        //8.获取用户录入的字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入访问路径: ");
        String path = sc.next();

        //9.根据用户录入的字符串,从Map集合中获取对应的Method对象
        Method method = map.get(path);
        if (method!=null){
            //10.执行Method,  invoke
            method.invoke(target);
        }else{
            System.out.println("404,您访问的资源不存在!");
        }
    }
}

此代码的作用为获取每一个有注解的方法 并且得到注解对象 读取注解对象的内容 把注解对象的内容 与 方法对象存储到map集合中  以注解对象的内容来确定每一个不同的方法 

getDeclaredAnnotation 为获取注解的实例化对象因为注解本质上是一个接口  可以访问其中的抽象方法 方法名为value 返回值为String 

动态代理:

概念: 创建对象的一种方式

作用:在不修改源码的情况下 增强方法  -------核心思想

//动态代理的方式创建接口的实现类对象, 会在内存中动态的生成一个该接口的实现类
public static Object newProxyInstance(
        ClassLoader loader, 类加载器(把字节码文件加载进内存!), 固定书写:                         本类名.class.getClassLoader()
        Class[] interfaces, 创建的对象要实现哪些接口,把这些接口的字节码文件对象放到一个数组中传递,固定书写: new Class[]{接口名.class,接口名.class...}
        InvocationHandler h, 将来创建的对象调用方法时, 现需要使用InvocationHandler来处理,编写方法的行为,固定书写 new InvocationHandler(){重写方法}

InvocationHandler也为一个函数式接口可以用lambda表达式创建匿名内部类

  

public interface Sale {

    //销售
    String sale(int money);

    //回收
    int recycle(String something);
}

 s为用动态代理的方法生成的Sale接口实现类对象

每一个对象调用方法时都会经过InvocationHandler接口的实现类对象处理 

public class Test02 {

    public static void main(String[] args) {
        //动态代理的方式创建Sale接口的实现类对象  Proxy
        //动态代理的方式创建接口的实现类对象, 会在内存中动态的生成一个该接口的实现类
        
            public static Object newProxyInstance(
                    ClassLoader loader, 类加载器(把字节码文件加载进内存!), 固定书写: Test02.class.getClassLoader()
                    Class[] interfaces, 创建的对象要实现哪些接口,把这些接口的字节码文件对象放到一个数组中传递,固定书写: new Class[]{接口名.class,接口名.class...}
                    InvocationHandler h, 将来创建的对象调用方法时, 现需要使用InvocationHandler来处理,编写方法的行为,固定书写 new InvocationHandler(){重写方法}
            )
         
        Sale s = (Sale) Proxy.newProxyInstance(Test02.class.getClassLoader(), new Class[]{Sale.class}, new InvocationHandler() {
            //invoke方法的作用, 将来使用创建好的实现类对象调用方法, 这个invoke会自动执行, 并且每调用一个方法, invoke会执行一次
            /*
                Object proxy: 不用关注!!!!
                Method method: 用户正在调用的方法
                Object[] args: 用户调用方法时传递的参数
             */
            //返回值类型就是方法执行的结果
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //System.out.println(method);
                //System.out.println(Arrays.toString(args));
                //用户现在调用的是哪个方法??
                String methodName = method.getName();
                if ("sale".equals(methodName)){
                    //sale方法的逻辑
                    System.out.println("收到"+args[0]+"元, 卖出晨光钢笔一支~");
                    return "晨光钢笔";
                }
                if ("recycle".equals(methodName)){
                    //recycle方法的逻辑
                    System.out.println("使用100块回收了: "+args[0]);
                    return 100;
                }
                return null;
            }
        });
        //使用对象调用方法
        String result = s.sale(999);
        System.out.println(result);
        int money = s.recycle("口罩");
        System.out.println(money);
    }
}

//ctrl+p: 查看方法参数

此为利用 动态代理 来增强 原接口实现类中方法 的效果

 public static Computer makeComputer() {
        //被代理对象
        Computer c = new ThinkPad();

        //使用动态代理造一台电脑,创建Computer接口的实现类对象
        //代理对象
        Computer proxy = (Computer) Proxy.newProxyInstance(
                ComputerFactory.class.getClassLoader(),
                new Class[]{Computer.class},
                new InvocationHandler() {
                    //每次调用方法后,invoke会自动执行
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //方法的实现方案
                        long start = System.currentTimeMillis();//开始时间

                        //执行method
                        Object result = method.invoke(c, args);

                        long end = System.currentTimeMillis();//结束时间
                        System.out.println("本次操作共耗时: " + (end - start));

                        return result;
                    }
                });
        return proxy;
    }
public interface Computer {
    void searchFile(String var1, String var2);

    void copyDir(String var1, String var2);
}
public class ThinkPad implements Computer {
    public ThinkPad() {
    }

    public void searchFile(String dir, String fileName) {
        File source = new File(dir);
        if (source.exists() && !source.isFile()) {
            File[] files = source.listFiles();
            File[] var5 = files;
            int var6 = files.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                File file = var5[var7];
                if (file.isDirectory()) {
                    this.searchFile(file.getAbsolutePath(), fileName);
                } else if (file.getName().contains(fileName)) {
                    System.out.println(file.getAbsolutePath());
                }
            }

        }
    }

    public void copyDir(String sourceDir, String targetDir) {
        try {
            FileUtils.copyDirectory(new File(sourceDir), new File(targetDir));
        } catch (IOException var4) {
            IOException e = var4;
            e.printStackTrace();
        }

    }
}
//用户
    public static void main(String[] args) {
        Computer computer = ComputerFactory.makeComputer();
        //ctrl+p: 查看参数
        computer.searchFile("C:\\Users\\Administrator\\Desktop\\JavaSE进阶","作业题");
        computer.copyDir("C:\\Users\\Administrator\\Desktop\\JavaSE进阶\\day01","C:\\Users\\Administrator\\Desktop\\JavaSE进阶\\day01_02");
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值