反射+注解


Java注解(Annotation)

1、含义

  • 在代码中的一种特殊标记,可以在程序编译,加载,运行时被编译器识别。在不改变代码逻辑的情况下,实现附加功能。

2、内置注解

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。

  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

    参数:value

    • 关键字 用途 解释
      all to suppress all warnings 抑制所有警告
      boxing to suppress warnings relative to boxing/unboxing operations 抑制装箱、拆箱操作时候的警告
      cast to suppress warnings relative to cast operations 抑制映射相关的警告
      dep-ann to suppress warnings relative to deprecated annotation 抑制启用注释的警告
      deprecation to suppress warnings relative to deprecation 抑制过期方法警告
      fallthrough to suppress warnings relative to missing breaks in switch statements 抑制在switch中缺失break的警告
      finally to suppress warnings relative to finally block that don’t return 抑制finally模块没有返回的警告
      hiding to suppress warnings relative to locals that hide variable 抑制与隐藏变量的局部变量相关的警告
      incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case) 忽略没有完整的switch语句
      nls to suppress warnings relative to non-nls string literals 忽略非nls格式的字符
      null to suppress warnings relative to null analysis 忽略对null的操作
      rawtypes to suppress warnings relative to un-specific types when using generics on class params 使用generics时忽略没有指定相应的类型
      restriction to suppress warnings relative to usage of discouraged or forbidden references 抑制有关使用不推荐或禁止使用的引用的警告
      serial to suppress warnings relative to missing serialVersionUID field for a serializable class 忽略在serializable类中没有声明serialVersionUID变量
      static-access to suppress warnings relative to incorrect static access 抑制不正确的静态访问方式警告
      synthetic-access to suppress warnings relative to unoptimized access from inner classes 抑制子类没有按最优方法访问内部类的警告
      unchecked to suppress warnings relative to unchecked operations 抑制没有进行类型检查操作的警告
      unqualified-field-access to suppress warnings relative to field access unqualified 抑制没有权限访问的域的警告
      unused to suppress warnings relative to unused code 抑制没被使用过的代码的警告

3、元注解

作用:可以对其他注解进行注解,可以用来编写自定义注解。

  • @Target: 用于描述注解的范围,即注解在哪用。它说明了Annotation所修饰的对象范围。

    参数:ElementType

    • CONSTRUCTOR:用于描述构造器
    • FIELD:用于描述域即类成员变量
    • LOCAL_VARIABLE:用于描述局部变量
    • METHOD:用于描述方法
    • PACKAGE:用于描述包
    • PARAMETER:用于描述参数
    • TYPE:用于描述类、接口(包括注解类型) 或enum声明
    • TYPE_PARAMETER:1.8版本开始,描述类、接口或enum参数的声明
    • TYPE_USE:1.8版本开始,描述一种类、接口或enum的使用声明
  • @Retention:用于描述注解的生命周期,表示需要在什么级别保存该注解,即保留的时间长短。

    参数:RetentionPolicy

  • SOURCE:在源文件中有效(即源文件保留)

  • CLASS:在class文件中有效(即class保留)

  • RUNTIME:在运行时有效(即运行时保留)

  • @Documented:描述注解会生成api文档。

    没有参数

  • @Inherited:被该注解声明的自定义注解,使用自定义注解的类,其子类会继承该自定义注解。只有在类上才有效。

4、自定义注解

  • 写法

    @Target({ElementType.TYPE,ElementType.METHOD})  //表明该注解只能在类上,方法上使用
    @Retention(RetentionPolicy.RUNTIME)     //表明该注解只在运行时有效
    @interface myAnnotation{
        //注解的参数格式:参数类型 + 参数名();
        String name();
        //该参数的默认值为22 使用注解时可以不传入参数
        int age() default 22;
    }
    
  • 使用

    @myAnnotation(name = "测试")
    public void test2(){
        
    }
    
  • 自定义注解只有一个参数时,使用value作为参数名。


Java反射(Reflection)

1、含义

  • 在程序运行中,可以构造一个类的对象;可以判断对象所属于哪个类;可以获取一个类中存在的属性和方法;可以调用一个类中的属性和方法。

2、反射的使用

  • 获取类的Class对象

    • 一个类在加载后,只会在内存中存在一个Class对象。

    • //方式一:根据对象的getClass方法获取Class对象
      Class c1 = person.getClass();
      
      //方式二:根据类名.class 方法获取
      Class c2 = Person.class;
      
      //方式三:根据类的全限定类名获取
      Class c3 = Class.forName("com.wt.annotation.Person");
      
      //包装类通过.TYPE属性获取Class对象
      Class c4 = Integer.TYPE;
      
  • 根据Class对象获取它的父类对象

    //获取Class对象的父类对象
    Class c5 = c1.getSuperclass();
    

3、Java中类会初始化的情况

  • Java虚拟机启动时,会初始化main方法所在的类。
  • new一个类的对象时,这个类会初始化。
  • 通过类名调用静态变量和静态方法时,这个类会被初始化。
  • 通过反射调用时,这个类会被初始化。
  • 当初始化一个类时,其父类会被先初始化。

4、Java的三种类加载器

  • 引导类加载器:由C++编写,用于加载Java的核心库,该加载器不能直接获取。

  • 扩展类加载器:用来加载Java的拓展库。

    //获取扩展类加载器		根据系统类加载器获取
    ClassLoader parent = systemClassLoader.getParent();
    
  • 系统类加载器:加载Java应用的类,开发人员编写的类由此加载器加载,是最常用的加载器。

    //获取系统类加载器
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    

5、通过反射获取类的信息

? c1:Class对象

  • 获取类名

    String name = c1.getName(); //全限定类名
    String simpleName = c1.getSimpleName(); //类名
    
  • 获取类中的属性

    Field[] fields = c1.getFields();	//获取类中公共属性
    Field[] declaredFields = c1.getDeclaredFields();	//获取类中所有属性
    //根据属性名获取类中的属性
    Field address = c1.getField("address");
    Field username = c1.getDeclaredField("username");
    
  • 获取类中的方法

    //获取该类及其父类的public修饰的方法集合
    Method[] methods = c1.getMethods();
    //获取该类中的所有方法集合
    Method[] declaredMethods = c1.getDeclaredMethods();
    //根据方法名获取类中的方法,有参时输入参数的Class对象	重载时区分方法
    Method getUsername = c1.getMethod("setUsername",String.class);
    Method test = c1.getDeclaredMethod("test");
    
  • 获取类的构造方法

    //获取类的公共构造器
    Constructor[] constructors = c1.getConstructors();
    //获取类中的所有构造器
    Constructor[] declaredConstructors = c1.getDeclaredConstructors();
    //获取指定的构造器,指定参数区分
    Constructor constructor = c1.getDeclaredConstructor(String.class, String.class, int.class, String.class);
    

6、反射动态创建对象

? c1:Class对象

  • c1.newInstance():根据Class对象创建对象。

  • 使用要求:类中必须拥有无参的构造方法,类中构造方法的访问权限,必须能够访问到。

  • 通过类的有参构造方法反射创建对象

    Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, String.class, String.class);
    User user = (User) constructor.newInstance(001, "张三", "123", "北京");
    
  • 通过反射操作方法

    • invoke():动态调用该方法,参数1:方法所属的对象;参数2:传入的值
    User user = (User) c1.newInstance();
    Method setAddress = c1.getDeclaredMethod("setAddress", String.class);
    setAddress.invoke(user,"重庆");
    
  • 通过反射操作属性

    • setAccessible(true):不能访问类中的私有属性时,调用该方法,设置参数为true,关闭程序的安全监测。默认为false,不能访问私有属性。
    • 使用反射时,关闭监测,会提高运行效率。
    User user = (User) c1.newInstance();
    Field username = c1.getDeclaredField("username");
    username.setAccessible(true);
    username.set(user,"李四");
    

7、通过反射操作注解

? c1:Class对象

  • 获取类上所有的注解

    Annotation[] annotations = c1.getAnnotations();
    
  • 获取类上指定的注解

    • 自定义注解

      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @interface Table{
          String value();
      }
      
    • 自定义注解的使用

      @Table("user")
      public class User {
      	......
      }
      
    • 获取类上指定的注解

      //获取注解
      Table table = (Table)c1.getAnnotation(Table.class);
      //获取注解的value值,	value="user"
      String value = table.value();
      
  • 获取类中属性上的注解

    • 自定义注解

      @Target(ElementType.FIELD)	//注解只能使用在属性上
      @Retention(RetentionPolicy.RUNTIME)
      @interface Column{
          String columnName();
          String type();
          int length();
      }
      
    • 自定义注解的使用

      @Column(columnName = "db_username",type = "varchar",length = 50)
      private String username;
      
    • 获取属性上注解

      Field username = c1.getDeclaredField("username");	//获取username属性
      Column column = username.getAnnotation(Column.class);	//获取username属性上的@Column注解
      String columnName = column.columnName();	//获取@Column注解的参数columnName的值
      String type = column.type();
      int length = column.length();