• 注解和反射详解以及运用


    注解

    概述和理解

    注解的开发已经是时代所趋向,未来的框架都是基于 注解 + 反射 + 设计模式

    在这里插入图片描述

    在这里插入图片描述

    JDK中的元注解

    元注解:对现有的注解进行解释说明以及限制(修饰注解的注解)

    JDK5.0提供了4个标准的元注解类型,分别是:

    • Retention:指明注解整体适用范围(默认是CLASS,反射时使用RUNTIME)
    • Target:指明注解能修饰哪些层面,例如类、方法、构造器(指明注解能修饰哪些层面,例如类、方法、构造器…)
    • Document:指明该注解编译后需不需要进入jdk文档
    • Inherited:注解能被继承

    使用

    注解能做什么呢?

    生成文档相关的注释

    在这里插入图片描述

    在编译时进行格式检查

    在这里插入图片描述

    跟踪代码的依赖,实现替代配置文件的功能

    类似这样的注解,省略了配置文件的复杂性

    在这里插入图片描述

    自定义注解

    • 用@interface声明注解
    • 内部定义成员,通常使用value表示
    • 用default定义成员的默认值
    • 若没有定义成员,表明是一个标识作用

    实现流程:

    1、IDEA中,新建class文件

    在这里插入图片描述

    2、写入代码

    ①、不写value,类似重写方法override

    在这里插入图片描述

    ②、写value,加默认值

    在这里插入图片描述

    3、其他地方使用

    在这里插入图片描述

    反射

    概述和理解

    反射相当于镜面,透过镜子看到类的结构, 通过反射可以对已有的实体对象进行解析

    反射最重要的用途就是开发各种通用框架:

    很多框架(比如 Spring)都是配置化的(比如Spring 通过 XML 配置模式装载 Bean),为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。

    优缺点

    优点

    使用反射机制,代码可以在运行时装配,提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需硬编码目标类

    缺点
    1. 性能问题:使用反射基本上是一种解释操作,JVM无法对这些代码进行优化,因此,反射操作的效率要比那些非反射操作低得多。反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,对性能要求高的程序中不建议使用

    2. 安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行

    3. 内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用——代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化

    疑问点

    1. 开发中既有反射也有new的方式建造对象,到底用哪个?

      平常使用new,如果是动态的话用反射(比如前后台的交互,你不确定调用哪个方法,这时候可以用反射来动态代理)

    2. 反射能调用私有,封装性隐藏私有,两者是否矛盾?

      不矛盾,因为封装是建议,而反射要看用在什么地方。两者都不禁止私有的运用

    哪些结构有反射

    在这里插入图片描述

    反射与动态代理

    在这里插入图片描述

    获取class实例的几个方式

    /**
     * 获取class实例的几种方式
     */
    public static void test3() throws Exception {
        //1、调用运行时类的属性
        Class clazz1 = Person.class;
        System.out.println(clazz1);
    
        //2、通过已知对象调用getClass()
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);
    
        //3、class静态方法:forName(String classPath)
        Class clazz3 = Class.forName("com.company.Person");
        System.out.println(clazz3);
    
        //4、使用类的加载器:ClassLoader(不常用)
        ClassLoader classLoader = Main.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.company.Person");
        System.out.println(clazz4);
    }
    
    /**
      * 拓展:使用classLoader加载配置文件
      */
    public static void test4() throws Exception {
        Properties pros = new Properties();
        //方式一:以前的方式(默认项目目录下)
        FileInputStream fis = new FileInputStream("src\\jdbc.properties");
        pros.load(fis);
    
        //方式二:类加载器的方式(默认src目录下)
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc.properties");
        pros.load(is);
    
        String username = pros.getProperty("username");
        String password = pros.getProperty("password");
        System.out.println("姓名:"+username+",密码:"+password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    调用指定的属性、方法

    /**
    * 调用person指定的属性
    */
    public static void testShuxing() throws Exception {
        Class<Person> personClass = Person.class;
        Person p = personClass.newInstance();
    
        //getDeclaredField:获取运行时类中指定的属性
        Field name = personClass.getDeclaredField("name");
        //保证属性能操作(私有、公有等权限都能操作)
        name.setAccessible(true);
    
        //name.set(null,"TOM");
        name.set(p,"TOM");
        System.out.println(name.get(p));
    
    }
    
    /**
     * 调用person指定的方法
     */
    public static void testMethod() throws Exception {
        Class<Person> personClass = Person.class;
        Person p = personClass.newInstance();
    
        //静态,正常方法都一样
        //getDeclaredMethod:获取运行时类中指定的方法
        Method showNation = personClass.getDeclaredMethod("showNation", String.class);
        //保证属性能操作(私有、公有等权限都能操作)
        showNation.setAccessible(true);
    
        //showNation.invoke(p, "CHINA");是直接调用此方法
        //如果拿东西接收,则接收的是此方法的返回值
        //showNation.invoke(null,"CHINA");
        Object china = showNation.invoke(p, "CHINA");
        System.out.println(china);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
  • 相关阅读:
    1785. 构成特定和需要添加的最少元素
    网站被劫持了怎么办
    第十四届蓝桥杯第一期模拟赛 python
    开漏输出,推挽输出,开集输出
    OpenShift 4 - 对 OpenShift 的 etcd 数据库加密
    7.js对象
    如何使用 Git 管理配置文件
    搭建简易Spring-ioc框架
    jvm启动流程
    原生JS实现拖拽排序
  • 原文地址:https://blog.csdn.net/qq_42709715/article/details/125395489