Java注解详解

2018-10-07  本文已影响0人  阿龙的学与思

虽然在平时开发中经常使用注解,却不知道如何自定义一个注解类型以及注解的实现原理。抽时间学习了一下,记录下来加深理解。

1. 注解是什么

之前看到一篇文章将注解理解为“标签”,感觉还是比较贴切的。我们可以把注解理解为给包、类、方法、字段打的一个标签,并利用java的反射机制对注解标注的类、方法或者字段进行相应的处理。

2. 定义注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String name() default "";
}

利用关键字@interface声明一个注解类型,并利用@Retention、@Target、@Document、@Inherited等元注解对注解进行定义。

public enum RetentionPolicy {
    /**
     * 注解只在源码文件中保留,不会被编译器编译
     */
    SOURCE,

    /**
     * 会被编译到生成的class文件中,但不会在运行时保留
     */
    CLASS,

    /**
     * 运行时有效,可以通过反射机制读取到该注解定义
     */
    RUNTIME
}
/**
 * 自定义注解AnnotationDemo、使用@Inherited表明该注解注解具有继承性
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String name() default "";
}
/**
 * 使用自定义注解修饰的父类
 */
@AnnotationDemo(name = "小明")
public class Super {
    public void hello(){
        System.out.println("I am super!");
    }
}
/**
 * 子类继承Super超类
 * 由于Super被@AnnotationDemo注解修饰,Child子类自动被@AnnotationDemo修饰,
 *
 */
public class Child extends Super {
    public void say(){
        System.out.println("I am child!");
    }
}

3. 注解的属性

在自定义注解时可以为注解定义若干属性,如在上边定义的@AnnotationDemo注解中定义了一个名为name的属性,默认值为""。注解类型只有属性没有方法,且注解属性声明为属性名+(),属性类型可以为基本类型、String、Class、Enum等类型。注解的属性使用default关键字声明该属性的默认值,如果不为属性声明默认值,则必须在使用注解时为该属性赋值。
特殊的:如果属性名为value,在使用注解时可以不指定属性名赋值。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String value() default "";
}
/**
 * @AnnotationDemo注解的属性名为value,使用时可以不指定属性名为属性赋值
 * 等价于@AnnotationDemo(value="super")
 */
@AnnotationDemo("super")
public class Super {
    public void hello(){
        System.out.println("hello world!");
    }
}

如果注解定义了多个属性,使用时不同的属性赋值用逗号分隔。

4. 注解与反射

正如在本文开头所说的注解相当于给类、方法、字段打的标签,对于运行时有效的注解需要通过JDK提供的反射机制来让标签起作用。下面通过一个简单的例子来演示如何利用反射机制使注解起作用。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Run {
    
}
public class RunTest {
    @Run
    public void test1(){
        System.out.println("run test1");
    }

    public void test2(){
        System.out.println("run test2");
    }
}
public class Main {

    public static void main(String[] args) throws ClassNotFoundException{
        try {
            Class clazz = Class.forName("com.annotation.demo.test.RunTest");
            Method[] methods = clazz.getMethods();
            RunTest junitTest =(RunTest) clazz.newInstance();
            for (Method method : methods){
                if (method.isAnnotationPresent(Run.class)){
                    method.setAccessible(true);
                    method.invoke(junitTest);
                }
            }
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }catch (InstantiationException e){
            e.printStackTrace();
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }catch (InvocationTargetException e){
            e.printStackTrace();
        }
    }
}

在这个例子中首先定义了一个@Run注解,并在RunTest中定义了两个方法。其中一个方法使用了@Run进行注解,另一个方法没有添加@Run注解,利用反射API对使用了@Run注解的方法进行调用。输出结果也正如我们所料:只有RunTest中的test1方法被执行。

OK,java注解的介绍就到这里。

你的关注是我持续更新的动力!

上一篇下一篇

猜你喜欢

热点阅读