Java自定义注解
注解在Java开发中有着广泛的运用,合理地运用注解,可以使得程序变得更加简洁。举例来说,方法覆写时,我们会在覆写的方法上看到@Override的注解等。可以说,看到这些注解,我们就能快速对注解施加影响的类、方法、属性等有个清晰的认识。
那么,什么是注解呢?
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。Java注解包含在
java.lang.annotation 包中。
其中,注解Annontation是Java5开始引入的新特征,中文名称就是注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。
Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
注解的用途主要有:
(1)生成文档。这是最常见的,也是java 最早提供的注解。
常用的有@param @return 等。
(2)跟踪代码依赖性,实现替代配置文件功能。
比如Dagger 2依赖注入,在java开发中会有大量注解配置,具有很大用处。
(3)在编译时进行格式检查。
如@override 放在方法前,如果这个方法并不是覆盖了超类方法,则编译时就能检查出。
那么,注解是基于什么原理呢?注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,
返回的是Java运行时生成的动态代理对象$Proxy。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法;
该方法会从memberValues这个Map中索引出对应的值,而memberValues的来源是Java常量池。
java.lang.annotation提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解):
@Documented –--注解是否将包含在JavaDoc中
@Retention –--什么时候使用该注解
@Target –--注解用于什么地方
@Inherited –--是否允许子类继承该注解
我们在编程中常见标准的注解Annotation有:
(1)Override
java.lang.Override是一个标记类型注解,它被用作标注方法。
它说明了被标注的方法重载了父类的方法,起到了断言的作用。
如果我们使用了这种注解在一个没有覆盖父类方法的方法时,
java编译器将以一个编译错误来警示。
(2)Deprecated
Deprecated也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated修饰的话,
编译器将不鼓励使用这个被标注的程序元素。
所以使用这种修饰具有一定的“延续性”:
如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,
虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。
(3)SuppressWarnings
SuppressWarning不是一个标记类型注解。
它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。
编译器会忽略掉无法识别的警告名。
为了深入了解注解,我在这里写一个自定义的注解案例,详见下述代码:
package com.itszt.annotation; import java.lang.annotation.*; /** * Annotation型定义为@interface, * 所有的Annotation会自动继承java.lang.Annotation这一接口, * 并且不能再去继承别的类或是接口. * * 参数成员只能用public或默认(default)这两个访问权修饰 * * 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean * 八种基本数据类型和String、Enum、Class、annotations等数据类型, * 以及这一些类型的数组. * * 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象, * 因为你除此之外没有别的获取注解对象的方法 * * 水果名称注解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitName { String value() default ""; } ------------------------------------------------------------ package com.itszt.annotation; import java.lang.annotation.*; /** * 水果颜色注解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitColor { /* *颜色枚举 */ public enum Color{RED,GREEN,YELLOW}; /* *颜色属性 */ Color fruitColor() default Color.GREEN; } ---------------------------------------------------- package com.itszt.annotation; import java.lang.annotation.*; /** * 水果供应者信息 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitProvider { /* *供应商编号 */ public int id() default -1; /* *供应商名称 */ public String name() default ""; /* *供应商地址 */ public String addr() default ""; } -------------------------------------------------------- package com.itszt.annotation; import java.lang.reflect.Field; /** * 注解处理器,这是注解施加作用的核心管理器 * 通过该处理器,达到对注解的使用 */ public class FruitInfoUtil { public static void getFruitInfo(Class<?> clazz){ String strFruitName="水果名称:"; String strFruitColor="水果颜色:"; String strFruitProvider="供应商信息:"; //通过反射获取属性上的注解 Field[] fields=clazz.getDeclaredFields(); for(Field field:fields){ if(field.isAnnotationPresent(FruitName.class)){ FruitName fruitName = field.getAnnotation(FruitName.class); strFruitName=strFruitName+(fruitName.value()); System.out.println(strFruitName); }else if(field.isAnnotationPresent(FruitColor.class)){ FruitColor fruitColor = field.getAnnotation(FruitColor.class); strFruitColor=strFruitColor+(fruitColor.fruitColor()); System.out.println(strFruitColor); }else if(field.isAnnotationPresent(FruitProvider.class)){ FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class); strFruitProvider=strFruitProvider+fruitProvider.id()+","+fruitProvider.name()+","+fruitProvider.addr(); System.out.println(strFruitProvider); } } } }
--------------------------------------------------------
package com.itszt.test;
/**
* 注解使用
*/
public class Apple {
@FruitName("苹果")
private String appleName;
@FruitColor(fruitColor = Color.YELLOW)
private String appleColor;
@FruitProvider(id = 1, name = "魏县红富士苹果园", address = "魏县东代固乡")
private String appleProvider;
public void setAppleColor(String appleColor) {
this.appleColor = appleColor;
}
public String getAppleColor() {
return appleColor;
}
public void setAppleName(String appleName) {
this.appleName = appleName;
}
public String getAppleName() {
return appleName;
}
public void setAppleProvider(String appleProvider) {
this.appleProvider = appleProvider;
}
public String getAppleProvider() {
return appleProvider;
}
}
-------------------------------------------------------
package com.itszt.test;
import com.itszt.annotation.FruitInfoUtil;
/**
* 通过注解处理器为实体类的属性赋值
*/
public class FruitRun {
public static void main(String[] args) {
FruitInfoUtil.getFruitInfo(Apple.class);
}
}
上述代码运行结果如下:
水果名称:苹果 水果颜色:YELLOW 供应商信息:1,魏县红富士苹果园,魏县东代固乡