注解
所谓注解,就是代码里面的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。
注解的使用方法
从某些方面来看,注解就像修饰一样的使用,可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被存储在注解的“name=value”对中。
基本的注解
@Override(只能作用于方法)
指定方法覆盖,强制一个子类必须覆盖父类的方法。它告诉编辑器检查这个方法,并从父类查找是否包含一个被该方法重写的方法,否则编译就出错。
作用:帮助程序员降低一些低级错误。比如子类B应该重写父类A的shot()方法,但是重写的时候写成了show()。
@Deprecated
表示某个程序元素(类、方法等)已过时,其他程序使用以国事的类、方法时,编译器会给出警告。
@SuppressWarnings
被该注解标记的程序元素以及在该元素中的所有子元素取消显示指定的编译器警告。
@SuppressWarnings(value="unchecked")
public class SuppressWarningsTest
{
public static void main(String[] args)
{
}
}
该程序取消了没有使用泛型的编译器警告
自定义注解
定义一个简单的注解
定义新的注解使用@interface关键字(在原有的interface关键字前增加@符号)。
//定义一个空的的注解类型
public @interface Test
{
}
注解还可以带成员变量,注解的成员变量的定义是以无参数的方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。
public @interface MyTag{
//定义了两个成员变量的注解
//以方法的形式来定义
String name();
int age();
}
定义了成员变量的注解的使用
public class Test{
@MyTag(name="xx",age=6)
public void info(){
...
}
}
使用default关键字为注解的成员变量时指定初始值
public @interface MyTag{
//定义了两个成员变量的注解
//以方法的形式来定义
String name() default "tom";
int age() default 7;
}
如果为注解的成员变量指定了默认值,那么在使用该注解时可以不为这些成员变量指定值,直接使用默认值。
public class Test{
//直接只用默认值,无需为注解的成员变量指定值
@MyTag
public void info(){
...
}
}
提取注解的信息
Java使用Annotation接口代表程序元素前面的注解,该接口是所有Annotation类型的父接口。
同时,Java在java.lang.reflect包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接口的主要实现类有:
Class:类定义
Constructor:构造器定义
Field:类的成员变量定义
Method:类的方法定义
Package:类的包定义
AnnotationElement接口是所有程序元素(如Class、Method和Constructor)的父接口,所以程序送过反射获取了某个类的AnnotatedElement对象之后,就可以通过调用该对象的下面三个方法访问注解信息
getAnnotation(Class annotationClass):返回该程序元素上存在的、指定类型的注解,如果该类型的注解不存在,则返回null。
Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该程序元素上是否存在指定类型的注解,存在返回true,否则返回false。
//Class.forName("Test"):获取Test类对象
//Class.forName("Test").getMethod("info"):获取对象的指定方法
Annotation[] aArray = Class.forName("Test").getMethod("info").getAnnotations();
for(Annotation an : aArray){
System.out.println(an);
}
若需要获取某个注解里面的元数据,则可以将注解牵制类型转化成所需要的注解类型,然后通过注解对象的抽象方法来访问这些元数据
Annotation[] annotation = tt.getClass().getMethod("info").getAnnotations();
for(Annotation tag : annotation){
if(tag instanceof MyTag1)//instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。
{
System.out.println("Tag is:"+ tag);
//将tag强制类型转换为MyTag1
//并调用tag对象的method1和method2两个方法
System.out.println("tag.name():"+((MyTag1)tag).method1());
System.out.println("tag.name():"+((MyTag1)tag).method2());
}
if(tag instanceof MyTag1)//
{
System.out.println("Tag is:"+ tag);
System.out.println("tag.name():"+((MyTag1)tag).method1());
System.out.println("tag.name():"+((MyTag1)tag).method2());
}
}
使用注解的例子
JDK中的元注解
JDK除了在java.lang下提供了3个基本的注解外,还在java.lang.annotation包下面提供了元注解(Meta Annotation),这四个元注解都是用于修饰其他注解定义
@Retention
@Retention 只能用于修饰一个注解定义,用于指定该注解可以保留多长时间。
@Retention下面包含了一个RetentionPolicy类型的value成员变量,所以使用该元注解时必须为该value成员变量指定值。其值只能是如下三个:
值 | 作用 |
---|---|
RetentionPolicy.CLASS(默认值) | 编译器将注解记录在class文件中,当运行Java程序时,JVM不再保留注解。 |
RetentionPolicy.RUNTIME | 编译器将注解记录在class文件中,当运行Java程序时,JVM也会保留注解。 |
RetentionPolicy.SOURCE | 编译器注解丢弃这种策略的注解。 |
@Target
用于指定被修饰的注解能用于修饰那些程序元素。
包含一个名为value的成员变量,其值只能是如下几个:
值 | 作用 |
---|---|
ElementType.ANNOTATION_TYPE | 指定该策略的Annotation只能修饰注解 |
ElementType.CONSTRUCTOR | 只能修饰构造器 |
ElementType.FIELD | 只能修饰成员变量 |
ElementType.LOCAL_VARIABLE | 只能修饰局部变量 |
ElementType.METHOD | 只能修饰方法 |
ElementType.PACKAGE | 只能修饰包 |
ElementType.PARAMETER | 可以修饰参数 |
ElementType.TYPE | 可以修饰类、接口(包括注解)或者枚举定义 |
@Cocumented
被修饰的注解类将被javadoc工具提取成文档,如果定义了注解类时用@Document修饰,则说有使用该注解修饰的的程序元素的API文档中将会包含该注解说明。
@Inherited
@Inherited修饰的注解将有继承性。
使用APT处理注解
APT(annotation processing tool)是一种处理注解的工具,他对源代码文件进行检测,找出其中过的注解后,使用注解进行额外的处理。
作用:简化开发者的工作量,因为APT可以在编译程序源代码时,生成一些附属文件(如源文件、类文件、程序发布描述性文字等等)