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

一)元注解简介

         在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
    
    
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您解答关于Java自定义字典类、自定义注解和反射注入字典值到实体类的问题。 首先,自定义字典类是一种将一些常量或者枚举类型的值封装在一起的方式。可以让代码更加易读、易维护。比如,我们可以定义一个字典类,用来存储一些常量值,如: ``` public class GenderDict { public static final Integer MALE = 1; public static final Integer FEMALE = 2; } ``` 接下来,我们可以使用自定义注解来标记需要注入字典值的实体类的属性上。比如,我们可以定义一个注解类,如: ``` @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Dictionary { String value(); } ``` 在该注解类中,我们使用@Retention和@Target注解来指定注解的保留策略和作用范围。同时,我们还可以使用value属性来指定注解的值,即该属性需要注入的字典值的名称。 最后,我们可以使用反射机制,在运行时动态地将字典值注入到实体类中。具体的实现方式如下: ``` public class DictionaryInjector { public static void injectDictionary(Object obj) throws IllegalAccessException { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Dictionary.class)) { Dictionary dict = field.getAnnotation(Dictionary.class); String dictName = dict.value(); String dictValue = getDictValue(dictName); field.setAccessible(true); field.set(obj, dictValue); } } } private static String getDictValue(String dictName) { // 从字典类中获取对应的字典值 // 这里可以使用反射或者其他方式来实现 return GenderDict.MALE.equals(dictName) ? "男" : "女"; } } ``` 在上述代码中,我们首先使用Class对象获取实体类的所有属性,然后通过判断该属性是否被@Dictionary注解标记来确定是否需要注入字典值。如果需要注入,则从注解中获取字典值的名称,然后通过反射机制将字典值注入到实体类的属性中。 最后,我们可以在代码中使用如下方式来注入字典值: ``` public class User { @Dictionary("gender") private String gender; // getters and setters } public class Main { public static void main(String[] args) throws IllegalAccessException { User user = new User(); DictionaryInjector.injectDictionary(user); System.out.println(user.getGender()); // 输出 "男" } } ``` 在上述代码中,我们首先定义了一个User类,并在其中使用@Dictionary注解标记了gender属性。然后,在Main类中,我们创建了一个User对象,并调用DictionaryInjector类的injectDictionary方法来注入字典值。最后,我们通过调用User对象的getGender方法来获取注入后的字典值。 希望这能够帮助您解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值