Java 注解

Posted kexinxin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 注解相关的知识,希望对你有一定的参考价值。

Java 注解

注解基础知识点

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

作用分类:

  1. 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
  2. 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
  3. 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

    Java注解,也叫元数据,外文名Annotation,是一种代码级别的说明

     

     

    Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以\'@注解名\'在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解,单值注解,完整注解三类。他们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制变成实现对这些元数据(用来描述数据的数据)的访问。另外,你可以再编译时选择代码里的注解是否存在于源代码级,或者它也能在class文件、或者运行时中出现。

     

     

     

     

    @Override,限定重写父类方法

    @Override 是一个标记注解类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。这个annotaton常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力。使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override即可。下面的代码是一个使用@Override修饰一个企图重载父类的displayName()方法,而又存在拼写错误的实例:

    public class Fruit {

        public void displayName(){

            System.out.println("水果的名字是:***");

        }

    }

    public class Apple extends Fruit{

        @Override

        public void displayname(){

            System.out.println("水果的名字是:苹果");

        }

    }

    public class Orange extends Fruit{

        @Override

        public void displayName(){

            System.out.println("水果的名字是:桔子");

        }

    }

     

    Orange 类编译不会有任何问题,Apple 类在编译的时候会提示相应的错误。@Override注解只能用于方法,不能用于其他程序元素。
    

     

     

    @Deprecated,标记已过时:

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

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

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

      下面一段程序中使用了@Deprecated注解标示方法过期,同时在方法注释中用@deprecated tag 标示该方法已经过时,代码如下:

     

    public class AppleService {

        public void displayName(){

            System.out.println("水果的名字是:苹果");

        }

        

        /**

         * @deprecated 该方法已经过期,不推荐使用

         */

        @Deprecated

        public void showTaste(){

            System.out.println("水果的苹果的口感是:脆甜");

        }

        

        public void showTaste(int typeId){

            if(typeId==1){

                System.out.println("水果的苹果的口感是:酸涩");

            }else{

                System.out.println("没有味道");

            }

        }

    }

     

    public class FruitRun {

        public static void main(String[] args) {

            Apple apple=new Apple();

            apple.displayName();

              

            AppleService appleService=new AppleService();

            appleService.showTaste();

            appleService.showTaste(0);

        }

    }

     AppleService类的showTaste() 方法被@Deprecated标注为过时方法,在FruitRun类中使用的时候,编译器会给出该方法已过期,不推荐使用的提示。

     

    SuppressWarnnings,抑制编译器警告:

      @SuppressWarnings 被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误。例如当我们使用一个generic collection类而又没有提供它的类型时,编译器将提示出"unchecked warning"的警告。通常当这种情况发生时,我们就需要查找引起警告的代码。如果它真的表示错误,我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case,那么我们就应增加一个默认的case来避免这种警告。
      有时我们无法避免这种警告,例如,我们使用必须和非generic的旧代码交互的generic collection类时,我们不能避免这个unchecked warning。此时@SuppressWarning就要派上用场了,在调用的方法前增加@SuppressWarnings修饰,告诉编译器停止对此方法的警告。
      SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
      annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值。实例如下:

     

    public class FruitService {

        @SuppressWarnings(value={"rawtypes","unchecked"})

        public static List<Fruit> getFruitList(){

            List<Fruit> fruitList=new ArrayList();

            return fruitList;

        }

        

        @SuppressWarnings("unused")

        public static void main(String[] args) {

            List<String> strList=new ArrayList<String>();

        }

    }

    在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员,所以只有一个简单的value={...}作为name=value对。又由于成员值是一个数组,故使用大括号来声明数组值。注意:我们可以在下面的情况中缩写annotation:当annotation只有单一成员,并成员命名为"value="。这时可以省去"value="。比如将上面方法getFruit()SuppressWarnings annotation就是缩写的。

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

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

     

     

     

     

     

     

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。

    元注解:

      元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
        1.@Target,
        2.@Retention,
        3.@Documented,
        4.@Inherited
      这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

    @Target

       @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packagestypes(类、接口、枚举、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 {

        public String tableName() default "className";

    }

    @Target(ElementType.FIELD)

    public @interface NoDBColumn {

     

    }

     

    注解Table 可以用于注解类、接口(包括注解类型) enum声明,而注解NoDBColumn仅可用于注解类的成员变量。

     

      @Retention

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

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

      取值(RetentionPoicy)有:

        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;

    }

     

     

    Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

     

    @Documented:

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

    @Target(ElementType.FIELD)

    @Retention(RetentionPolicy.RUNTIME)

    @Documented

    public @interface Column {

        public String name() default "fieldName";

        public String setFuncName() default "setField";

        public String getFuncName() default "getField";

        public boolean defaultDBValue() default false;

        

    }

    @Inherited

      @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

      注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation

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

      实例代码:

    @Inherited

    public @interface Greeting {

        public enum FontColor{BULE,RED,GREEN};

        String name();

        FontColor fontColor() default FontColor.GREEN;

        

    }

    自定义注解:

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

      定义注解格式:
      public @interface 注解名 {定义体}

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

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

      Annotation类型里面的参数该怎么设定
      

    以上是关于Java 注解的主要内容,如果未能解决你的问题,请参考以下文章

    JAXB的@XmlElement注解

    java代码在片段活动中不起作用

    Android APT注解处理器 ( 根据注解生成 Java 代码 )

    java 代码片段【JAVA】

    # Java 常用代码片段

    # Java 常用代码片段