反射与注解

反射:框架设计的灵魂

1.反射机制的理解

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
  • 反射:将类的各个组成部分封装为其他对象,就是把java类中的各种成分映射成一个个的Java对象
  • 反射机制:Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    • 好处:
      1. 可以在程序运行过程中,操作这些对象。
      2. 可以解耦,提高程序的可扩展性。
      3. 简单来说就是Java可以加载一个运行时候才得知名称的class,获得其完整的构造,并生成实例化对象,对其成员变量赋值,调用其方法等等。
  • 反射机制简单理解为动态获取类中的信息。
    在这里插入图片描述

2.Java代码在计算机中经历的三个阶段

在这里插入图片描述

第一个阶段(源代码阶段):

先从java文件按成员变量,构造方法,成员方法通过javac编译成.class文件。如上图Person.java–>Person.class

第二个阶段(Class类对象阶段):

通过类加载器把.class文件中的成员变量,构造方法,成员方法加载到内存中。

第三个阶段(Runtime运行时阶段):

该阶段就可以创建对象和调用对象里的方法了。

3 获取Class对象的方式:

获取Class对象的方式:

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象

    Class cls1 =Class.forName("cn.itcast.domain.Person");

    • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
  2. 类名.class:通过类名的属性class获取

    Class cls2 = Person.class;

    • 多用于参数的传递
  3. 对象.getClass():getClass()方法在Object类中定义着。

    Person p = new Person();
    Class cls3 = p.getClass();

  • 结论:
    同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
3.1 Class对象功能:
  • 获取功能:
    1. 获取成员变量们

      • Field[] getFields() :获取所有public修饰的成员变量

      • Field getField(String name) 获取指定名称的 public修饰的成员变量

      • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

      • Field getDeclaredField(String name)

    2. 获取构造方法们

      • Constructor<?>[] getConstructors()

      • Constructor getConstructor(类<?>… parameterTypes)

      • Constructor getDeclaredConstructor(类<?>… parameterTypes)

      • Constructor<?>[] getDeclaredConstructors()

    3. 获取成员方法们:

      • Method[] getMethods()

      • Method getMethod(String name, 类<?>… parameterTypes)

      • Method[] getDeclaredMethods()

      • Method getDeclaredMethod(String name, 类<?>… parameterTypes)

    4. 获取全类名

      • String getName()
3.2 Field:成员变量
  • 操作:
    1. 设置值

      • void set(Object obj, Object value)
    2. 获取值

      • get(Object obj)
    3. 忽略访问权限修饰符的安全检查

      • setAccessible(true):暴力反射
3.3 Constructor:构造方法
  • 创建对象:
    • T newInstance(Object… initargs)

    • 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

3.4 Method:方法对象
  • 执行方法:

    • Object invoke(Object obj, Object… args)
  • 获取方法名称:

    • String getName:获取方法名

注解:代码级别的说明

1.注解的理解

  • 概念:说明程序的。给计算机看的

  • 注释:用文字描述程序的。给程序员看的

  • 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

  • 概念描述:

    • JDK1.5之后的新特性
    • 说明程序的
    • 使用注解:@注解名称

2. 注解作用分类:

①编写文档:通过代码里标识的注解生成文档【javadoc xxx.java生成文档doc文档(API文档)】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

3. 注解的种类

3.1 JDK中预定义的一些注解
  • @Override :检测被该注解标注的方法是否是继承自父类(接口)的

  • @Deprecated:该注解标注的内容,表示已过时

  • @SuppressWarnings:压制警告

    • 一般传递参数all @SuppressWarnings("all"),卸载类前面压制该类所有警告,写在方法里压制该方法所有警告
    /**
     * JDK中预定义的一些注解
     * 		* @Override	:检测被该注解标注的方法是否是继承自父类(接口)的
     * 		* @Deprecated:该注解标注的内容,表示已过时
     * 		* @SuppressWarnings:压制警告
     */
    
    @SuppressWarnings("all")
    public class AnnoDemo2 {
    
        @Override
        public String toString() {
            return super.toString();
        }
    
        @Deprecated
        public void show1(){
            //有缺陷
        }
    
        public void show2(){
            //替代show1方法
        }
    
        public void demo(){
            show1();
            Date date = new Date();
        }
    }
    
    
3.2. 自定义注解
  • 格式:
    元注解
    public @interface 注解名称{
    属性列表;
    }

    public @interface MyAnno {
    
         int value();
        Person per();
        MyAnno2 anno2();
        String[] strs();
         /*String name() default "张三";*/
         /*String show2();
    
         Person per();
         MyAnno2 anno2();
    
         String[] strs();*/
    
    
    }
    
  • 本质:注解本质上就是一个接口,该接口默认继承Annotation接口

    • public interface MyAnno extends java.lang.annotation.Annotation {}
  • 属性:接口中的抽象方法

    • 要求:

      1. 属性的返回值类型有下列取值

        • 基本数据类型
        • String
        • 枚举
        • 注解
        • 以上类型的数组
      2. 定义了属性,在使用时需要给属性赋值

        1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。

        2. 如果只有一个属性需要赋值,并且属性的名称是value(特殊值),则value可以省略,直接定义值即可。

        3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

          @MyAnno(value=12,per = Person.P1,anno2 = @MyAnno2,strs={"bbb","ccc"})
          public class Worker {
          }
          
3.3. 元注解:用于描述注解的注解
  • @Target:描述注解能够作用的位置

    • ElementType枚举取值:

      • TYPE:可以作用于类上

      • METHOD:可以作用于方法上

      • FIELD:可以作用于成员变量上

@Target(value={ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) (value可以省略)

  • @Retention:描述注解被保留的阶段

    • @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到,自定义注解一般定义在RUNTIME阶段
  • @Documented:描述注解是否被javadoc抽取到api文档中

  • @Inherited:描述注解是否被子类继承

  • 在程序使用(解析)注解:获取注解中定义的属性值(其实就是抽象方法),注解大多用于替换反射中的配置文件的

    1. 获取注解定义着的位置的对象 (Class对象,Method对象, Field对象)

      Class<ReflectTest> reflectTestClass = ReflectTest.class;//获取该类的字节码文件对象

    2. 获取指定的注解

      • getAnnotation(Class)
        其实就是在内存中生成了一个该注解接口的子类实现对象

        Pro an = reflectTestClass.getAnnotation(Pro.class);

        //上面的代码相当于执行了下面的功能,就是在内存中生成了一个该注解接口的子类实现对象 
        public class ProImpl implements Pro{
               public String className(){
                   return "cn.itcast.annotation.Demo1";
               }
               public String methodName(){
                   return "show";
               }
           }
        
    3. 调用注解中的抽象方法获取配置的属性值

    //3.调用注解对象中定义的抽象方法,获取返回值
            String className = an.className();
            String methodName = an.methodName();
            System.out.println(className);//注解里配置的属性值,类名
            System.out.println(methodName);//注解里配置的属性值,方法名
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值