Java注解

来源:互联网 发布:windows Api编程过程 编辑:程序博客网 时间:2024/06/06 00:42

概述

注解是提高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 descriptionI am method descriptionI am field descriptionI am field description
0 0
原创粉丝点击