Java元注解的实战应用-实体类注解封装(下)

来源:互联网 发布:网络女主播直播换衣服 编辑:程序博客网 时间:2024/06/14 12:59

一)元注解简介

         在java.lang.annotation包下,定义了6个元注解。元注解就是修饰注解的注解。

        拿到一个注解,如何知道它是否是元注解呢?需要看它的元注解(无论是元注解还是普通注解都是有元注解的),如果看到这样的元注解:@Target(ElementType.ANNOTATION_TYPE),那么此时这个注解一定是元注解。

  • @Retention

  • @Target

  • @Documented

  • @Inherited

  • @Repeatable  (java 8新增)

  • 类型注解

@Repetable和类型注解暂时不介绍

1.1 @Retention

@Retention用于指定注解可以保留多长时间(生命周期)。

@Retention包含一个名为“value”的成员变量,该value成员变量是RetentionPolicy枚举类型。使用@Retention时,必须为其value指定值。value成员变量的值只能是如下3个:

  • RetentionPolicy.SOURCE:Annotation只保留在源代码中,编译器编译时,直接丢弃这种Annotation,不记录在.class文件中。

  • RetentionPolicy.CLASS:编译器把Annotation记录在class文件中。当运行Java程序时,JVM中不可获取该Annotation信息。这是默认值

  • RetentionPolicy.RUNTIME:编译器把Annotation记录在class文件中。当运行Java程序时,JVM可获取该Annotation信息,程序可以通过反射获取该Annotation的信息。

示例:

[java] view plain copy
  1. package com.demo1;  
  2.   
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5.   
  6. //name=value形式  
  7. //@Retention(value=RetentionPolicy.RUNTIME)  
  8.   
  9. //直接指定  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. public @interface MyTag{  
  12.     String name() default "我兰";  
  13. }  

如果Annotation里有一个名为“value“的成员变量,使用该Annotation时,可以直接使用XXX(val)形式为value成员变量赋值,无须使用name=val形式。

1.2 @Target

@Target指定Annotation用于修饰哪些程序元素。@Target也包含一个名为”value“的成员变量,该value成员变量类型为ElementType[ ]ElementType为枚举类型,值有如下几个:

  • ElementType.TYPE:能修饰类、接口或枚举类型

  • ElementType.FIELD:能修饰成员变量

  • ElementType.METHOD:能修饰方法

  • ElementType.PARAMETER:能修饰参数

  • ElementType.CONSTRUCTOR:能修饰构造器

  • ElementType.LOCAL_VARIABLE:能修饰局部变量

  • ElementType.ANNOTATION_TYPE:能修饰注解

  • ElementType.PACKAGE:能修饰包

示例1(单个ElementType):

[java] view plain copy
  1. package com.demo1;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Target;  
  5.   
  6. @Target(ElementType.FIELD)  
  7. public @interface AnnTest {  
  8.     String name() default "测试Target";  
  9. }  

示例2(多个ElementType):

[java] view plain copy
  1. package com.demo1;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Target;  
  5.   
  6. @Target(<span style="color:#cc0000">{ ElementType.FIELD, ElementType.METHOD }</span>)  
  7. public @interface AnnTest {  
  8.     String name() default "测试target!";  
  9. }  

1.3 @Documented

如果定义注解A时,使用了@Documented修饰定义,则在用javadoc命令生成API文档后,所有使用注解A修饰的程序元素,将会包含注解A的说明。

示例:

[java] view plain copy
  1. @Documented  
  2. public @interface Testable {  
  3. }  
[java] view plain copy
  1. public class Test {  
  2.     @Testable  
  3.     public void info() {  
  4.     }  
  5. }  

1.4 @Inherited

       @Inherited指定注解具有继承性。如果某个类使用了@xxx注解(定义该注解时使用了@Inherited修饰)修饰,则其子类将自动被@xxx修饰

示例:

[java] view plain copy
  1. package com.demo2;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Inherited;  
  5. import java.lang.annotation.Retention;  
  6. import java.lang.annotation.RetentionPolicy;  
  7. import java.lang.annotation.Target;  
  8.   
  9. @Target(ElementType.TYPE)  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Inherited  
  12. public @interface MyTag{  
  13.   
  14. }  
[java] view plain copy
  1. package com.demo2;  
  2.   
  3. @MyTag  
  4. public class Base {  
  5.   
  6. }  
[java] view plain copy
  1. package com.demo2;  
  2.   
  3. //SubClass只是继承了Base类  
  4. //并未直接使用@MyTag注解修饰  
  5. public class SubClass extends Base {  
  6.     public static void main(String[] args) {  
  7.         System.out.println(SubClass.class.isAnnotationPresent(MyTag.class));  
  8.     }  
  9. }  

           示例中Base使用@MyTag修饰,SubClass继承Base,而且没有直接使用@MyTag修饰,但是因为MyTag定义时,使用了@Inherited修饰,具有了继承性,所以运行结果为true。

          如果MyTag注解没有被@Inherited修饰,则运行结果为:false。

 二)元注解语法及定义形式

(1)以@interface关键字定义

(2)注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
上面的语法不容易理解,下面通过例子来说明一下,这个例子就是Target注解的源码,

源码分析如下:
         第一:元注解@Retention,成员value的值为RetentionPolicy.RUNTIME。
         第二:元注解@Target,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
         第三:成员名称为value,类型为ElementType[]
另外,需要注意一下,如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
       @Retention(RetentionPolicy.RUNTIME)
       @Target(ElementType.ANNOTATION_TYPE)


三)简单实例应用——实体类注解封装

1)主键id注解

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * * * @author xiu * @version 2017年8月4日 上午11:17:05  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Id {/**ID生成策略 * @return */public Strategy strategy() default Strategy.IDENTITY;/**ID序号 * @return */public int sort() default 0;public static enum Strategy{/** * 自定义ID */IDENTITY,/** * 自增长ID */AUTO}}

2)索引index注解

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *数据库索引属性 * * @author xiu * @version 2017年8月4日 上午11:23:23  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Index {/** * 索引名字 * @return */public String[] names() default {};/** * 索引引用的列名 * @return */public String[] indexs() default {};/** * 索引的类型 * @return */public Type[] types() default {};/** * 索引的方式 * @return */public Way[] ways() default {};public static enum Type {NORMAL(""),//普通UNIQUE("UNIQUE"),//唯一FULLTEXT("FULLTEXT");//全参数private String value;private Type(String value){this.value = value;}public String value() {return this.value;}}public static enum Way {BTREE("BTREE"),//tree方式HASH("HASH");//hash方式private String value;private Way(String value) {this.value = value;}public String value() {return this.value;}}}

3)注释column

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *表字段注解 * @author xiu * @version 2017年8月4日 上午11:13:09  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Column {/**字段长度,仅对String生效 * @return */public int length()  default 255;/**备注 * @return */public String comment();}

4)父类MappedSuperclass注解

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *父类注解 * * @author xiu * @version 2017年8月4日 上午11:42:21  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface MappedSuperclass {}

5)@Transient注解

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *非持久化属性 * * @author xiu * @version 2017年8月4日 上午11:48:50  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Transient {}

6)表名@Table

package com.xiu.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *数据库表的属性 * * @author xiu * @version 2017年8月4日 上午11:45:17  */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Table {/** * 表名 * @return */public String name() default "";/** * 分表数 * @return */public int catalog() default 0;/** * 结合catalog的组合定义 * 例如catalog = 10,catalog_ = 0,分表数为0到9 * 例如catalog = 6,catalog_ = 1,分表数为1到5 *  * @return */public int catalog_() default 0;/** * 分表根据字段 * @return */public String catalogby() default "";/** * 表注释 * @return */public String comment() default "";}

7)使用方式

          这种实体类相关注解的使用在实际开发中非常频繁,封装起来的数据库实体注解特别在服务端游戏开发中应用更为广泛。

package com.xiu.annotation.entity;import java.io.Serializable;import java.util.List;import com.xiu.annotation.Column;import com.xiu.annotation.Id;import com.xiu.annotation.Id.Strategy;import com.xiu.annotation.Index;import com.xiu.annotation.Table;import com.xiu.annotation.Transient;/** *游戏战斗道具实体类 * * @author xiu * @version 2017年8月4日 上午11:55:03  */@Table(name = "game_battle_item", comment = "游戏战斗道具")@Index(names = {"rid"}, indexs = {"rid"})public class Item implements Serializable {private static final long serialVersionUID = 4496679862865864947L;@Id(strategy=Strategy.AUTO)    @Column(comment = "id")    private long id;    @Column(comment = "玩家id")    private long rid;    @Column(comment = "道具id")    private int itemId;    @Column(comment = "道具数量")    private int num;        //不持久化的临时数据    @Transient    private List<Integer> itemIdList;        //getter、setter        }