注意:所有文章除特别说明外,转载请注明出处.
注解
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注意:Annotation是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来取得注解里的元数据。此外Annotation不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一的执行。访问和处理Annotation的工具统称API。
注解的API:
Package java.lang.annotation
1.注解的应用结构图
调用/结构关系:A<–B<–C
现在对A,B,C解释如下:
A:注解类
@interface A{
}
B:应用了“注解类”的类
@A
Class B{
}
C:对“应用了注解类的类”进行反射操作的类
Class C{
public void f(){
B.class.isAnnotationPresent(A.class);
A a = B.class.getAnnotion(A.class);
}
}
2.元注解
元注解的作用就是负责注解其他注解。四个元注解分别是:@Target,@Retention,@Documented,@Inherited
- @Retention
表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy中,包括RetentionPolicy.SOURCE,RetentionPolicy.CLASS(默认),RetentionPolicy.RUNTIME分别对应:java源文件–>class文件–>内存中的字节码
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
- @Target 表示该注解用于什么地方,可能的值在枚举类ElemenetType中,包括
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
@Documented 将此注解包含在javadoc中,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当于@see,@param等
@Inherited 允许子类继承父类中的注解
@Override 限定重写父类方法 用来指定覆盖的,它可以强制一个子类必须覆盖父类的方法。@Override 主要帮助程序员避免一些低级错误。@Override只修饰方法,不能修饰其他元素。
@Deprecated 用于表示某个程序元素(类、方法等)已经过时,当其他程序使用已过时的类、方法时,编译器将发出警告
@SupperessWarnings 抑制编译器警告 指示被该Annotation修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定编译器警告。@SupperessWarnings会一直作用于该程序的所有子元素。
@SafeVarargs Java把引发这种错误的原因称为”堆污染”,当把一个不带泛型的对象赋给一个带泛型的变量时,往往会发生这种”堆污染”。
3.自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
1.定义注解格式:
public @interface 注解名 {定义体}
2.注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
3.示例代码
参考【参考资料】中 java 注解的几大作用及使用方法详解(完)
下面的示例,是上文提到的A<–B<–C的扩充版本。自定义了一个注解@A,然后在B类中使用了注解@A,最后在类C中利用反射读取@A中的信息
A.java
package com.iot.annotation;
import java.lang.annotation.*;
/**
* Created by brian on 2016/2/20.
*/
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface A {
String name();
int id() default 0;
Class<Long> gid();
}
B.java
package com.iot.annotation;
import java.util.HashMap;
import java.util.Map;
/**
* Created by brian on 2016/2/20.
*/
@A(name="type",gid=Long.class)//类注解
public class B {
@A(name="param",id=1,gid=Long.class) //类成员注解
private Integer age;
@A(name="construct",id=2,gid=Long.class) //构造方法注解
public B(){}
@A(name="public method",id=3,gid=Long.class) //类方法注解
public void a(){
}
@A(name="protected method",id=4,gid=Long.class) //类方法注解
protected void b(){
Map<String,String> m = new HashMap<String,String>(0);
}
@A(name="private method",id=5,gid=Long.class) //类方法注解
private void c(){
Map<String,String> m = new HashMap<String,String>(0);
}
public void b(Integer a){
}
}
C.java
package com.iot.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* Created by brian on 2016/2/20.
*/
public class C {
/**
* 简单打印出B类中所使用到的类注解
* 该方法只打印了 Type 类型的注解
* @throws ClassNotFoundException
*/
public static void parseTypeAnnotation() throws ClassNotFoundException{
Class clazz = Class.forName("com.iot.annotation.B");
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation :annotations){
A a = (A)annotation;
System.out.println("id = "+a.id()+" ;name = "+a.name()+" ;gid = "+a.gid());
}
}
/**
* 简单打印出B类中所使用到的方法注解
* 该方法只打印了 Method 类型的注解
*/
public static void parseMethodAnnotation() {
Method[] methods = B.class.getDeclaredMethods();
for (Method method : methods) {
/*
* 判断方法中是否有指定注解类型的注解
*/
boolean hasAnnotation = method.isAnnotationPresent(A.class);
if (hasAnnotation) {
/*
* 根据注解类型返回方法的指定类型注解
*/
A annotation = method.getAnnotation(A.class);
System.out.println("method = " + method.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= " + annotation.gid());
}
}
}
/**
* 简单打印出B类中所使用到的方法注解
* 该方法只打印了 Method 类型的注解
*/
public static void parseConstructAnnotation(){
Constructor[] constructors = B.class.getConstructors();
for (Constructor constructor : constructors) {
/*
* 判断构造方法中是否有指定注解类型的注解
*/
boolean hasAnnotation = constructor.isAnnotationPresent(A.class);
if (hasAnnotation) {
/*
* 根据注解类型返回方法的指定类型注解
*/
A annotation =(A) constructor.getAnnotation(A.class);
System.out.println("constructor = " + constructor.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= "+annotation.gid());
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
parseMethodAnnotation();
parseConstructAnnotation();
}
}