Java注解(Annotation)
什么是注解?
Annotation是Java5开始引入的新特征,中文名称叫注解。它用来将元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
Java注解是附加在代码中的一些元数据,用于一些工具编译、运行时进行解析==(通过反射)==和使用,起到说明、配置的功能。注解不能直接干扰程序代码的运行,无论增加或者删除注解,代码都能正常运行。
注解的用处
- 编写文档:通过代码里标识的元数据生成文档。常见有@param @return等。
- 代码分析:通过代码里面标识元数据对代码进行分析。
- 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
系统注解
标准注解
Java提供了5个基本的注解用法
-
@Override:限定重写父类方法,它可以强制一个子类必须覆盖父类的方法。写在子类的方法上,在编译期,编译器检查这个方法,检查父类必须包含该方法,否则编译出错。该注解只能修饰方法,在编译期被读取。
-
@Deprecated:用于表示某个程序元素已过时或者可能运行时出现问题。编译时读取,编译器编译到过时元素会给出警告。
-
@SuppressWarnings:抑制编译警告。被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显式指定的编译警告。
-
@SafeVarargs:Java7新增,去除“堆污染”警告。堆污染-------把一个不带泛型的对象赋值给一个带泛型的变量时就会发生堆污染。
List l2 = new ArrayList<Number>(); List<String> ls = l2; Arrays源代码 @SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
-
@FunctionInterface:Java8新增,修饰函数式接口。使用该注解修饰的接口必须是函数式接口,不然编译会出错。函数式接口------如果接口中只有一个抽象方法(可以包含多个default方法或者static方法),就是函数式接口。
@Functionlnterface public interface FunInterface{ static void foo(){ System.out.println("foo类方法"); } default void bar(){ System.out.println("bar默认方法"); } void test();//只定义一个抽象方法,默认public }
元注解
元注解:和元数据一样,修饰注解的注解。
-
@Target(目标)
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }
用于指定被修饰的注解能用于哪些程序元素上。它包含一个名为value的成员变量,取值如下:
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }
-
@Retention(保留)
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
用于指定被修饰注解的生命周期。它包含一个value的成员变量,取值如下:
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
SOURCE 在编译阶段被丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码文件。@Override、@SuppressWarnings都属于这类注解。 CLASS 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。 RUNTIME 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解信息。 -
@Documented
用于指定被修饰的注解将被Javadoc工具取成文档,即说明该注解将被包含在Javadoc中。
-
@Inherited
用于指定被修饰的注解具有继承性。即子类可以继承父类中的该注解。
自定义注解
使用关键字@interface
注解元素数据类型
- 所有基本类型(int、float、boolean等)
- String
- Class
- enum
- Annotation
- 以上类型的数组
一个简单的注解
@interface test{}
默认情况下,注解可以修饰任何程序元素(类、方法、接口、属性)等。
带成员变量的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
String name();
int id() default 0;
}
@DBTable(name = "student")
public class Test01 {
}
以无形参的方法形式来声明注解的成员变量。使用default关键字设置初始值,没设置初始值的变量则使用时必须提供,有初始值的变量可以设置也可以不设置。
结论
- 没有成员变量的注解 ----标记注解(marker annotation)这种注解仅利用自身的存在与否来提供信息。
- 有成员变量的注解----单值注解、完整注解 这种注解提供更多元数据。
获取注解信息
思路:通过反射获取注解,将注解转换成具体的注解类,在调用注解类定义的方法获取元数据信息。
java.lang.reflect.AnnotatedElement接口 代表程序中可以接受注解的程序元素。常见实现类:
- Class:类定义
- Constructor:构造器定义
- Field:类的成员属性定义
- Method:类的方法定义
- Package:类的包定义
AnnotatedElement接口获取注解信息的方法如下:
-
-
Modifier and Type Method and Description <T extends Annotation>T
getAnnotation(Class<T> annotationClass)
返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。Annotation[]
getAnnotations()
返回此元素上 存在的注释。default <T extends Annotation>T[]
getAnnotationsByType(Class<T> annotationClass)
返回与此元素相关 联的注释 。default <T extends Annotation>T
getDeclaredAnnotation(Class<T> annotationClass)
如果这样的注释 直接存在 ,则返回指定类型的元素注释,否则返回null。Annotation[]
getDeclaredAnnotations()
返回 直接存在于此元素上的注释。default <T extends Annotation>T[]
getDeclaredAnnotationsByType(Class<T> annotationClass)
如果此类注释 直接存在或 *间接存在,*则返回该元素的注释(指定类型)。default boolean
isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果此元素上 存在指定类型的注释,则返回true,否则返回false。
-
举例
注解处理器
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBField {
int id() default 0;
String value();
}
public class Test01 {
public static void main(String[] args) throws Exception{
User user = new User();
Class clazz = user.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
DBField dbField = field.getAnnotation(DBField.class);
System.out.println("id = "+dbField.id()+"\t"+"value = "+dbField.value());
}
}
}