1. annotation(注解)含义
- 注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。
- annotation是Java提供的一种元程序中的元素关联任何信息和任何元数据(metadata)的途径和方法。
- annotation是一个接口,程序可以通过反射来获取指定程序元素的annotation对象,然后通过annotation对象来获取注解里面的元数据。
- annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation的“name=value”结构对中。
2. 自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。
- @interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。
- 方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
2.1 自定义注解格式:
/**
* 自定义注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface 注解名 {
注解体
}
2.2 参数设置:
- 只能用public或default这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
- 参数成员只能用基本类型(byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,Stringvalue();这里的参数成员就为String;
- 如果只有一个参数成员,最好把参数名称设为"value",后加小括号。 例如:
/**
* xxx注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface xxx {
String value() default "";
}
2.3 注解元素的默认值
- 注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。
- 因此,使用空字符串或0作为默认值是一种常用的做法。
2.4 注解处理器类库(java.lang.reflect.AnnotatedElement)
(1)注解元素使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。
(2)除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接口主要有如下几个实现类:
Class
:类定义Constructor
:构造器定义Field
:类的成员变量定义Method
:类的方法定义Package
:类的包定义
2.5 访问annotation的信息
- 方法1:
<T extends Annotation> T getAnnotation(Class<T>annotationClass)
返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null; - 方法2:
Annotation[] getAnnotations()
返回该程序元素上存在的所有注解; - 方法3:
boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)
判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false; - 方法4:
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
3. 示例
自定义xxx注解–>编写注解解析器–>在某个类中使用注解–>注解测试
/**
* 自定义球颜色注解
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BallColor {
public enum MyColor {
YELLOW,BLUE,GREEN,BLACK,RED,PINK
}
public MyColor ballColor() default MyColor.BLUE;
}
/**
* 自定义球类别注解
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BallType {
String value() default "ball";
}
/**
* 注解解析器
*/
public class BallParser {
public static void getBallInfo(Class<?> clazz){
String strBallColor = "球颜色:";
String strBallType = "球类别:";
//得到所有方法包括私有方法,返回一个数组
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields) {
//判断该程序元素上是否包含指定类型的注解
if (field.isAnnotationPresent(BallColor.class)) {
BallColor ballColor = (BallColor)field.getAnnotation(BallColor.class);
strBallColor = strBallColor + ballColor.ballColor().toString();
System.out.println(strBallColor);
}
if (field.isAnnotationPresent(BallType.class)) {
BallType ballType = (BallType)field.getAnnotation(BallType.class);
strBallType = strBallType + ballType.value();
System.out.println(strBallType);
}
}
/**
* 在类中使用注解
*/
public class Ball {
@BallType
private String ballType;
@BallColor(ballColor=MyColor.GREEN)
private String ballColor;
public String getBallType() {
return ballType;
}
public void setBallType(String ballType) {
this.ballType = ballType;
}
public String getBallColor() {
return ballColor;
}
public void setBallColor(String ballColor) {
this.ballColor = ballColor;
}
}
/**
* 注解测试
*/
public class BallTest {
public static void main(String[] args){
BallParser.getBallInfo(Ball.class);
}
}