09.Java 基础 - 注解

基本概念

Annotion (注解)是一个接口,程序可以通过反射来获取指定程序元素的 Annotion 对象,然后通过 Annotion 对象来获取注解里面的元数据。

根据注解的使用方法和用途,我们可以将 Annotation 分为三类:系统注解,元注解,自定义注解。


系统注解

系统注解,即 JDK 内置的注解,主要有:@Override,@Deprecated,@SuppressWarnnings。

1.@Override

修饰方法时表示该方法覆盖了父类的方法,或实现接口的方法

interface Demo{
    public void print();
}

public class Test implements Demo{
    @Override
    public void print() {
    }
}

2.@Deprecated

修饰已经过时的方法

Alt text


3.@SuppressWarnnings

抑制编译器警告,即去除警告。

常见的参数值有:

名称作用
rawtypes表示传参时也要传递带泛型的参数
deprecation使用了不赞成使用的类或方法时的警告
unchecked执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型
fallthrough当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
path在类路径、源文件路径等中有不存在的路径时的警告;
serial当在可序列化的类上缺少 serialVersionUID 定义时的警告;
finally任何 finally 子句不能正常完成时的警告;
all关于以上所有情况的警告。

实例如下:

// 抑制单类型
@SuppressWarnings("unchecked")
public void print() {
    @SuppressWarnings("rawtypes")
    List list = new ArrayList(); 
    list.add("a");
}

// 抑制多类型
@SuppressWarnings({ "unchecked", "rawtypes" })
public void print() {
    List list = new ArrayList(); 
    list.add("a");
}

// 抑制所有类型
@SuppressWarnings({ "all" })
public void print() {
    List list = new ArrayList(); 
    list.add("a");
}

元注解

元注解的作用就是负责注解其他注解。Java5.0 定义了4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明。

定义的元注解如下:@Target,@Retention,@Documented,@Inherited。


1.@Target

@Target 定义了 Annotation所修饰的对象范围,具体的修饰范围如下:

public enum ElementType {
    // 用于描述类、接口(包括注解类型) 或enum声明
    TYPE,

    // 用于描述域(即变量)
    FIELD,

    // 用于描述方法
    METHOD,

    // 用于描述参数
    PARAMETER,

    // 用于描述构造器
    CONSTRUCTOR,

    // 用于描述局部变量
    LOCAL_VARIABLE,

    // 用于描述注解类型
    ANNOTATION_TYPE,

    // 用于描述包
    PACKAGE
}

2.@Retention

@Retention 定义了该 Annotation 被保留的时间长短,即指明了 Annotation 的生命周期。

public enum RetentionPolicy {

    // 在源文件中有效(编译器要丢弃的注解)
    SOURCE,

    // class 文件中有效(默认,编译器将把注解记录在类文件中,但在运行时 VM 不需要保留注解)
    CLASS,

    // 在运行时有效(编译器将把注解记录在类文件中,在运行时 VM 将保留注解,因此可以反射性地读取)
    RUNTIME
}

3.@Documented

@Documented 定义 Annotation ,表示某一类型的注解将通过 javadoc 和类似的默认工具进行文档化。

如果类型声明是用 Documented 来注解的,则其注解将成为注解元素的公共 API 的一部分。


4.@Inherited

@Inherited 定义 Annotation ,表示注解类型被自动继承,即一个使用了@Inherited 修饰的annotation 类型被用于一个 class,则这个 annotation 将被用于该class的子类。

  • 使用注解类型注解 class 以外的任何事物,@Inherited 都是无效的。

  • 此元注解仅促成从父类继承注解;对已实现接口的注解无效。

  • 当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层

实例如下:

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface MyAnotation{
    public String name();
}

// 作用在类上
@MyAnotation(name="parent")
class Parent{

}

// 继承 Parent 类
public class Test extends Parent{
    public static void main(String[] args) {
        Class<?> cls = Test.class;
        // 通过 @Inherited 继承父类的注解
        Annotation annotation = cls.getAnnotation(MyAnotation.class);
        MyAnotation myAnotation = (MyAnotation) annotation;
        System.out.println(myAnotation.name());
    }
}

// 输出结果:parent(若注释掉注解,返回异常)

自定义注解

1.类注解

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation {
    public String name();
    public String age();
}

// 调用注解
@MyAnnotation(name="cook",age="100")
public class Test {
    public static void main(String[] args) {
        Class<?> cls = Test.class;

        // 1.取得所有注解
        Annotation[] annotations =cls.getAnnotations();

        // 2.取得指定注解
        MyAnnotation annotation = 
            (MyAnnotation)cls.getAnnotation(MyAnnotation.class);
    }
}   

2.方法注解

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
// 修改作用范围
@Target(ElementType.METHOD)
@interface MyAnnotation {
    public String name();

    public String age();
}

// 调用注解
public class Test {

    public static void main(String[] args) throws Exception {
        Class cls = Test.class;
        Method method = cls.getDeclaredMethod("print", null);

        // 1.取得所有注解
        Annotation[] annotations = method.getDeclaredAnnotations();

        // 2.取得指定注解
        MyAnnotation annotation = 
            (MyAnnotation)method.getAnnotation(MyAnnotation.class);
    }

3.参数注解

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
// 修改作用范围
@Target(ElementType.PARAMETER)
@interface MyAnnotation {
    public String name();
    public String age();
}

public class Test {

    public static void main(String[] args) throws Exception {
        Class cls = Test.class;
        Method method = cls.getDeclaredMethod("print", new Class[]{String.class,String.class});
        getAllAnnotations(method);
    }

    // 作用在参数上
    public void print(@MyAnnotation(name = "cook", age = "100") 
        String name, String age) { }

    public static void getAllAnnotations(Method method) {
        Annotation[][] parameterAnnotions = method.getParameterAnnotations();

        // 通过反射只能取得所有参数类型,不能取得指定参数
        Class[] paraemterTypes = method.getParameterTypes();
        int i = 0;
        for (Annotation[] annotations : parameterAnnotions) {
            Class paraemterType = paraemterTypes[i++];
            for (Annotation annotation : annotations) {
                if (annotation instanceof MyAnnotation) {
                    MyAnnotation myAnnotation = (MyAnnotation) annotation;
                    System.out.println(paraemterType.getName());
                    System.out.println(myAnnotation.name());
                    System.out.println(myAnnotation.age());
                }
            }
        }
    }
}

4.变量注解

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
// 修改作用范围
@Target(ElementType.FIELD)
@interface MyAnnotation {
    public String name();
    public String age();
}

public class Test {
    // 作用在变量上
    @MyAnnotation(name = "cook", age = "100")
    private String name;

    public static void main(String[] args) throws Exception {
        Class cls = Test.class;
        Field field = cls.getDeclaredField("name");
        Annotation[] fieldAnnotions = field.getDeclaredAnnotations();
        MyAnnotation annotation = 
            (MyAnnotation) field.getAnnotation(MyAnnotation.class);
    }
}

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值