注解(Annotation)介绍

来源:互联网 发布:对号入座的网络词 编辑:程序博客网 时间:2024/05/01 22:29
一、内置系统注解:
        JavaSE中内置三个标准注解,定义在java.lang中:
       @Override:用于修饰此方法覆盖了父类的方法。
        是一个标记注解(一个没有成员定义的Annotation类型被称为标记注解。这种Annotation类型仅使用自身的存在与否来为我们提供信息),它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。这个annotaton常常在我们试图覆盖父类方法而却又写错了方法名时发挥威力。使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override即可。
class Orange extends Fruit {    @Override    public void displayName(){        System.out.println("水果的名字是:桔子");    }}
       @Deprecated:用于修饰已经过时的方法。

        是一个标记注解。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的 “延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。

  值得注意,@Deprecated这个annotation类型和javadoc中的 @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述)。

  在java5.0,java编译器仍然象其从前版本那样寻找@deprecated这个javadoc tag,并使用它们产生警告信息。但是这种状况将在后续版本中改变,我们应在现在就开始使用@Deprecated来修饰过时的方法而不是 @deprecated javadoc tag。

/*** @deprecated 该方法已经过期,不推荐使用*/@Deprecatedpublic void showTaste(){    System.out.println("水果的苹果的口感是:脆甜");}
       @SuppressWarnnings:用于通知java编译器禁止特定的编译警告。

        被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0,sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误
        SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告 名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
   annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对,用于为annotation的成员赋值。 

        SuppressWarnings注解的常见参数值的简单说明:

     1.deprecation:使用了不赞成使用的类或方法时的警告;

              2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 

              3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;

              4.path:在类路径、源文件路径等中有不存在的路径时的警告; 

              5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 

              6.finally:任何 finally 子句不能正常完成时的警告; 

              7.all:关于以上所有情况的警告。

@SuppressWarnings({ "rawtypes", "unchecked" })public static  List<Fruit> getFruit(){    List<Fruit> fruitList=new ArrayList();    return fruitList;}
二、元注解:

        元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:

1@Target

        说明Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

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

        取值(ElementType)有:

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

示例:

@Target(ElementType.TYPE)public @interface Table {    //用于注解类、接口(包括注解类型) 或enum声明,默认值为类名称    public String tableName() default "className";}@Target(ElementType.FIELD)public @interface Column {    //用于注解成员变量(域)}

2、@Retention

        定义Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”进行限制。

        作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

   取值(RetentionPolicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

  Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

示例:

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Column {    public String name() default "fieldName";    public String setFuncName() default "setField";    public String getFuncName() default "getField";     public boolean defaultDBValue() default false;}

3、@Documented

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

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Column {    public String name() default "fieldName";    public String setFuncName() default "setField";    public String getFuncName() default "getField";     public boolean defaultDBValue() default false;}

4、@Inherited

        也是一个标记注解,阐述了某个被标注的类型是可被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

示例:

@Inheritedpublic @interface Greeting {    public enum FontColor{ BULE,RED,GREEN};    String name();    FontColor fontColor() default FontColor.GREEN;}

三、自定义注解:

        使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

        定义注解格式:

            public @interface 注解名 {定义体}

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

            1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)

            2.String类型

            3.Class类型

            4.enum类型

            5.Annotation类型

            6.以上所有类型的数组

        Annotation类型里面的参数设定规则: 

            1)只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型; 

            2)参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  

            3)如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

            4)注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

示例:

/**  * 颜色枚举  */ enum FruitColor {GREEN,YELLOW,RED}


import java.lang.annotation.*;@Target(ElementType.TYPE)  @Retention(RetentionPolicy.RUNTIME)  @Documented  /** * 类注解 */public @interface Name {String fruitName() default "apple";}

import java.lang.annotation.*;@Target(ElementType.FIELD)  @Retention(RetentionPolicy.RUNTIME)  @Documented /** * 域注解 */public @interface Taste {      String fruitTaste() default "sweet";  } 


import java.lang.annotation.*;@Target(ElementType.METHOD)  @Retention(RetentionPolicy.RUNTIME)  @Documented  /** * 方法注解 */public @interface Color {      /**      * 颜色属性      */      FruitColor fruitColor() default FruitColor.GREEN;  }  

/** * 定义一种水果并使用注解 */@Name(fruitName="banana")public class Fruit{     private FruitColor color;    @Taste(fruitTaste="sour")    private String taste;         public FruitColor getColor() {return color;}public void setColor(FruitColor color) {this.color = color;}@Color    public FruitColor turnColor(FruitColor color){    this.color=color;    return color;    }}  


import java.lang.annotation.Annotation;import java.lang.reflect.*;/* * 解析注解 */public class FavourateFruit {public static void main(String args[]){System.out.println("Name是否是注解类型:"+Name.class.isAnnotation());System.out.println("Fruit类的Name注解是:"+Fruit.class.getAnnotation(Name.class));System.out.println("Fruit类的Name注解的属性值是:"+Fruit.class.getAnnotation(Name.class).fruitName());System.out.println("**********************************开始解析类注解********************************");//获取类上的所有注解System.out.println("类名称:"+Fruit.class.getSimpleName());    Annotation[] cAnnotations = Fruit.class.getAnnotations();    for(Annotation tmp : cAnnotations){    //类注解    if(tmp.annotationType() == Name.class){            System.out.println("类注解名称:"+Name.class.getSimpleName());            Method[] methods = Name.class.getDeclaredMethods();     for(Method method : methods){                 System.out.println("类注解属性:"+method.getName());                 System.out.println("类注解属性值:"+Fruit.class.getAnnotation(Name.class).fruitName());             }        }    }    System.out.println("**************************类注解解析结束,开始解析域注解***************************");    Field[] fields = Fruit.class.getDeclaredFields();    for(Field field : fields){    System.out.println("类的成员变量名:"+field.getName());    Annotation[] fAnnotations = field.getAnnotations();    for(Annotation tmp :fAnnotations){    if(tmp.annotationType() == Taste.class){    System.out.println("成员变量注解名称:"+Taste.class.getSimpleName());    Method[] methods = Taste.class.getDeclaredMethods();       for(Method method : methods){                   System.out.println("类注解属性:"+method.getName());                   System.out.println("类注解属性值:"+field.getAnnotation(Taste.class).fruitTaste());               }    }    }    }    System.out.println("************************域注解解析结束,开始解析方法注解***************************");    //获取类中方法的所有注解    Method[] methods = Fruit.class.getDeclaredMethods();    for(Method tmp:methods){    System.out.println("类的方法名:"+tmp.getName());    Annotation[] mAnnotations = tmp.getAnnotations();    for(Annotation tmp1:mAnnotations){    if(tmp1.annotationType() == Color.class){    System.out.println("方法的注解名称:"+Color.class.getSimpleName());    System.out.println("方法的注解属性:"+tmp.getAnnotation(Color.class));    System.out.println("方法注解的属性值:"+tmp.getAnnotation(Color.class).fruitColor());    }    }    }    }}

参考:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

0 0
原创粉丝点击