一、java内置注解
@Override:标识覆盖超类中的方法。
@Deprecated:使用了该注解的,编译器会发出警告信息。
@SuppressWarnings:关闭编译器警告。
二、定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
public String name();
public String des() default "default des";
}
定义注解时,需要为其制定元注解,用来描述注解将用于什么地方,@Target,@Retention即为元注解。
四种元注解:
@Target:标识注解应该用于什么地方–CONSTRUCTOR(构造器声明),FIELD(域声明,包括enum实例),LOCAL_VARIABLE(局部变量声明),METHOD(方法),PACKAGE(包),PARAMETER(参数),TYPE(类、接口或enum)。
@Retention:表示在什么级别保存该注解信息–SOURCE(源代码),CLASS(类文件),RUNTIME(运行时)。
@Documented:将此注解包含在Javadoc中。
@Inherited:允许子类继承父类中的注解
name和des的定义类似于方法定义,而不是变量定义:
public String name;
public String des;
default给予des一个默认值。
使用eg:
public class TestUse{
@Test(name = "method1", des = "exec mothod1")
public void method1(){
...
}
@Test(name = "method2") //没有给des赋值,使用默认值
public void method2(){
...
}
@Test(des = "exec mothod3")
public void method3(){
...
}
}
没有元素的注解,称为标记注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test2{
}
三、注解处理器
public class TestTracker{
public static void trackTest(Class<?> c) {
for(Method m : c.getDeclareMethods()) {
Test t = c.getAnnotaion(Test.class);
if (null != t) {
System.out.println(t.id() + "-----" + t.des());
}
}
}
}
public static void main(String[] args) {
testTracker(TestUse.class)
}
c.getAnnotaion(XXX.class) : 返回指定类型的注解对象,没有该类型注解则返回null。
用于变量的注解eg:
注解构建:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestField{
}
使用:
public class MyField{
@TestField
private String name;
@TestField
ptivate int age;
public void testFieldAnnotaion() {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
TestField anno = field.getAnnotation(TestField.class);
if (null != anno) {
//业务处理
...
}
}
}
}
四、嵌套注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseAnno{
boolean target() default false;
boolean isDefault() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestNestingAnno{
String name() default "";
BaseAnno baseAnno() default @BaseAnno;
}
public class TestNestingField {
@BaseAnno
@TestNestingAnno(name = "test", baseAnno = @ BaseAnno(idDefault = true))
String testField;
}
五、注解不支持继承
注解不能通过extends继承
六、使用apt处理注解
apt是sun为了帮助注解处理过程而提供的注解处理工具
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface TestAptAnno{
String name();
}
public class TestAptAnnoProcessor extends AbstractProcessor {
// 初始化工作
@Override
public synchronized void init(ProcessingEnvironment env){
super.init(env);
}
//处理逻辑,控制代码生成
@Override
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) {
...
return ture;
}
//支持的注解类型列表
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>();
set.add(TestAptAnno.class.getCanonicalName());
return set;
}
//支持的java版本信息
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
@TestAptAnno(name = "测试apt")
public class TestClass{
public static void main(String[] args) {
...
}
}
通过继承AbstractProcessor.java,可实现我们自己的注解处理器,在getSupportedAnnotationTypes() 方法中可指定注解的列表,在process()方法中,写我们自己的代码生成逻辑。