Java 注解(1)注解Annotation的定义,内置注解,元注解

1.注解概念

Java 注解可以通过反射获取注解内容。在编译器生成类文件时,注解可以被嵌入到字节码中
Java 虚拟机可以保留注解内容,在运行时可以获取到注解内容 。 当然它也支持自定义 Java 注解。

2.Java内置注解

5 个用于通知编译器信息的注解
@Override :空注解,用于标记那些覆盖父类方法的方法,如果父类没有这个方法,或者复写的方法访问权限比父类的权限小,编译器就会报错
@Deprecated : 空注解,用于标记那些不应该被使用的代码,如果使用了过时的代码,编译器会发出警告
@SafeVarargs : 空注解,(varargs 可变参数)用于标记构造函数或者方法,通知编译器,这里的可变参数相关的操作保证安全
@FunctionInterface : Java SE 8 出现的,用于通知编译器,这个类型是 function 接口
@SuppressWarning:抑制错误,可以用于标记整个类、某个方法、某个属性或者某个参数,用于告诉编译器这个代码是安全的,不必警告

4个作用在注解的注解(元注解)
@Documented:让注解信息出现在 document 中

@Retention : 指出注解如何存储,支持以下三种参数

  • RetentionPolicy.SOURCE : 注解只保留在源码中,编译时会忽略
  • RetentionPolicy.CLASS : 更高一级,编译时被编译器保留,但是运行时会被 JVM 忽略
  • RetentionPolicy.RUNTIME : 最高级,运行时会被保留,可以被运行时访问

@Target :指出注解作用于(修饰)什么对象,支持以下几种参数

  • ElementType.TYPE : 作用于任何类、接口、枚举
  • ElementType.FIELD : 作用于一个域或者属性
  • ElementType.METHOD : 作用于一个方法
  • ElementType.PARAMTER : 作用于参数
  • ElementType.CONSTRUCTOR : 作用于构造函数
  • ElementType.LOCAL_VARIABLE : 作用于本地变量
  • ElementType. ANNOTATION_TYPE : 作用于注解
  • ElementType.PACKAGE : 作用于包

@Inherited :当前注解是否可以继承

3.自定义注解

3.1Java元注解源代码

首先看看几个典型的Java自带的元注解的源代码是怎么写的:

  • @Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@interface表示这里定义了一个注解
@Target(ElementType.METHOD)作用于方法;
@Retention(RetentionPolicy.SOURCE)表示信息仅存在于编译器处理期间,编译器处理完之后SuppressWarnings就没有作用了。

  • @SuppressWarnings
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
       String[] value();
}

大部分字段与@Override中类似;
特别关注下value()这个字段,表示我们在使用@SuppressWarnings时候可以给它传参。
传参使用示例如下:
@SuppressWarnings("unchecked")
告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
@SuppressWarnings("serial")
如果编译器出现这样的警告信息:The serializable class WmailCalendar does notdeclare a static final serialVersionUID field of type long使用这个注释将警告信息去掉。
@SuppressWarnings("deprecation")
如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。使用这个注释将警告信息去掉。
@SuppressWarnings("unchecked", "deprecation")
告诉编译器同时忽略unchecked和deprecation的警告信息。
@SuppressWarnings(value={"unchecked", "deprecation"})
等同于@SuppressWarnings("unchecked", "deprecation")

3.2自定义注解

注解的通用定义方法是,使用@interface语法。
比如自定义一个简单的注解MyAnnotation1:需要采用@interface标识,并辅以元注解进行标注,并且自己去实现注解的具体业务解释代码

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}

在元注解的源代码中,比如@Override,可以看到并没有具体处理逻辑,它只是一个修饰作用,告诉编译器这个方法要覆盖父类的方法,编译器会去检查父类有没有这个方法。
原因:元注解是由注解编译器实现了业务逻辑代码(在java代码里无法看到实现,应该是在编译器里有具体的实现)。

下面是一个完整的自定义注解,包括其与反射结合的使用示例
Annotation在反射函数中的使用示例

package JavaAdvancedCharateristic.Annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

//用@interface,自定义一个注解
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String[] value() default "unknown";//如果不传参,则采用参数的默认值unknown
}

/**
 * Person类。它会使用MyAnnotation注解。
 */
class Person {

    /**
     * empty()方法同时被 "@Deprecated" 和 “@MyAnnotation(value={"a","b"})”所标注
     * (01) @Deprecated,意味着empty()方法,不再被建议使用
     * (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
     */
    @MyAnnotation
    @Deprecated
    public void empty() {
        System.out.println("\nempty");
    }

    /**
     * sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注,
     *
     * @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"}
     */
    @MyAnnotation(value = {"girl", "boy"})
    public void somebody(String name, int age) {
        System.out.println("\nsomebody: " + name + ", " + age);
    }
}

public class AnnotationTest {

    public static void main(String[] args) throws Exception {

        // 新建Person
        Person person = new Person();
        // 获取Person的Class实例
        Class<Person> c = Person.class;
        // 获取 somebody() 方法的Method实例
        Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
        // 执行该方法
        mSomebody.invoke(person, new Object[]{"lily", 18});
        iteratorAnnotations(mSomebody);


        // 获取 somebody() 方法的Method实例
        Method mEmpty = c.getMethod("empty", new Class[]{});
        // 执行该方法
        mEmpty.invoke(person, new Object[]{});
        iteratorAnnotations(mEmpty);
    }

    public static void iteratorAnnotations(Method method) {

        // 判断 somebody() 方法是否包含MyAnnotation注解
        if (method.isAnnotationPresent(MyAnnotation.class)) {
            // 获取该方法的MyAnnotation注解实例
            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
            // 获取 myAnnotation的值,并打印出来
            String[] values = myAnnotation.value();
            for (String str : values)
                System.out.printf(str + ", ");
            System.out.println();
        }

        // 获取方法上的所有注解,并打印出来
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }
}

运行结果:
运行结果:
somebody: lily, 18
girl, boy,
@com.skywang.annotation.MyAnnotation(value=[girl, boy])

empty
unknown,
@com.skywang.annotation.MyAnnotation(value=[unknown])
@java.lang.Deprecated()

posted @ 2020-04-17 14:17  JohnTesla  阅读(488)  评论(0编辑  收藏  举报