Java注解

    xiaoxiao2021-03-25  57

    概述

    注解是提高Java开发效率的重要工具。

    通过注解,很多配置文件和逻辑可以用注解来代替,使代码更加简洁,清晰。因此,大部分的开源框架都大量使用了注解,例如Spring中,注解配合反射实现的控制反转是其核心理念之一。注解的内容涵盖如图的内容:

    我将挑选其中必须的部分讲述。

    注解介绍:

    如图是java.lang.annotation包的结构:

    我们发现里面包含一个Annotation接口,五个以“@”开头的注释,三个相关的Error和Exception,以及两个Enum类型。

    下面是一个我写的自定义注释:

    @Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @interface Description{ String value(); }

    注解定义

    注解的标志是@interface,编译器会使它自动继承java.lang.annotation.Annotation接口,做一系列的工作将它编译成一个注解。在定义注解时,不能继承其他的注解或接口。

    元注解

    注解前面的@Target,@Retention等是注解的注解,称为元注解。

    共有:@Target,@Retention,@Inherited,@Documented,@Native五个注解。

    @Target:

    用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

    取值使用了枚举类型(ElementType),有:

        1.CONSTRUCTOR:用于描述构造器     2.FIELD:用于描述域     3.LOCAL_VARIABLE:用于描述局部变量     4.METHOD:用于描述方法     5.PACKAGE:用于描述包     6.PARAMETER:用于描述参数     7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

    @Retention

    用于描述注解的保留时间,

    取值也是枚举类型(RetentionPolicy),有:

    1.SOURCE,在原文件中有效 2.CLASS,在class文件中有效 3.RUNTIME,运行期间有效

    @Inherited

    用于描述注释可以被继承,即如果这个注解应用于一个父类,它的子类也将拥有这个注解。

    @Docemented

    用于描述注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

    @Native

    表示定义了一个可能被本地方法使用的常量,这个注解被一些工具用来识别已加载必要的头文件。

    注解体

    注解体中只能定义一系列的属性,不能定义方法。被注解的对象类似于继承了这些属性。

    注解参数的可支持数据类型:

        1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)     2.String类型     3.Class类型     4.enum类型     5.Annotation类型     6.以上所有类型的数组

    注解参数的默认值:

    注解参数可以设定默认值,如

    @interface Palette{ public enum Color {RED,YELLOW,BLUE,WHITE}; String color() default Color.WHITE; String name default ""; }

    默认属性value 任何一个注解都有一个默认属性value(String类型)。例如,当在一个类上加了@MyAnnotation(“hello”)的注释,这个类就类似于继承了MyAnnotation的属性,其中必然有的属性是value,值为“hello”。

    JDK中的注解:

    @Override 重载 @Deprecated 过时 @SuppressWarnnings 抑制编译器警告     SuppressWarnings注解的常见参数值的简单说明:

        1.deprecation:使用了不赞成使用的类或方法时的警告;     2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;     3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;     4.path:在类路径、源文件路径等中有不存在的路径时的警告;     5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;     6.finally:任何 finally 子句不能正常完成时的警告;     7.all:关于以上所有情况的警告。

    注解使用

    AnnotatedElement

    注解必须被使用才有意义,使用的方法是通过反射。核心的接口是java。lang.reflect.AnnotatedElement。接口的outline如下:

    isAnnotationPresent()判断类是否有注解,返回boolean类型。 getAnnotation(Class <T>)寻找特定的注解类型,返回注解对象,没有这个类型的注解,则返回空。 getAnnotations()寻找对象所包含的注解类型数组,如果有重复的注解,每个类型只计一个。 getAnnotationsByType()返回特定注解类型的注解数组。

    这里就需要说到重复注解的问题:

    如下:

    @Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @Repeatable(Descriptions.class) @interface Description{ String value(); int put() default 1; } @Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @interface Descriptions{ Description[] value(); }

    当一个注解在另一个注解中以数组形式存在,并且被注解为Repeatable,那么这个注解可以在一个对象上多次注解。比如在Web应用里注册多个过滤器,拦截器。

    对于重复注解,getAnnotations()只能获得一次,但getAnnotationsByType()可以就获得多次。

    而下面的

    getDeclaredAnnotation(); getDeclaredAnnotations(); getDeclaredAnnotationsByType();

    则是只获取本类的注解,忽略类所继承的类和实现的接口的注解。

    通过源码可以发现,反射相关的类如,Field,Constructor,Method都继承Executable类,Executable类继承AccessbaleObject,AccessbaleObject实现了AnnotationElement接口。

    所以这些类可以使用以上方法来获取注解,然后以类似类的方法,获取注解中的属性,如下例所示。

    package com.way.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Method; public class LearnAnnotation { public static void main(String[] args) { Class c=null; try { c=Class.forName("com.way.annotation.F"); if(c.isAnnotationPresent(Description.class)){ Description d=(Description)c.getAnnotation(Description.class); System.out.println(d.value()); Method[] ms=c.getMethods(); for(Method m:ms){ if(m.isAnnotationPresent(Description.class)){ Description dd=m.getAnnotation(Description.class); System.out.println(dd.value()); } } Field[] fs=c.getFields(); for(Field f:fs){ if(f.isAnnotationPresent(Description.class)){ Description ddd=f.getAnnotation(Description.class); System.out.println(ddd.value()); } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }

    一个辅助的类,对该类添加注解

    package com.way.annotation; @Description("I am class description") class F{ @Description("I am method description") public String getName(){ return null; } @Description("I am field description") public String name; @Description("I am field description") public int id; public int age; }

    控制台输出,可以看到,可以获取到相应注解的内容

    I am class description I am method description I am field description I am field description
    转载请注明原文地址: https://ju.6miu.com/read-34993.html

    最新回复(0)