Java注解的使用【奔跑吧!JAVA】

举报
多米诺的古牌 发表于 2021/05/12 17:07:19 2021/05/12
【摘要】 一、简介注解是一种特殊的接口,注解继承自 java.lang.annotation.Annotation1.所有注解类型都会继承 Annotation 接口2.手工显示继承 Annotation 接口,不会定义成一个注解类型3.Annotation 本身并不会定义成一个注解类型二、分类注解可以分为 元注解、内置注解、用户自定义注解2.1 元注解一种基本注解,可以应用在其它的注解上。可以这样理...

一、简介

注解是一种特殊的接口,注解继承自 java.lang.annotation.Annotation

1.所有注解类型都会继承 Annotation 接口

2.手工显示继承 Annotation 接口,不会定义成一个注解类型

3.Annotation 本身并不会定义成一个注解类型

二、分类

注解可以分为 元注解内置注解用户自定义注解

2.1 元注解

一种基本注解,可以应用在其它的注解上。可以这样理解,元注解是用于标记注解的注解

元注解有:

  • java.lang.annotation.Retention
  • java.lang.annotation.Target
  • java.lang.annotation.Documented
  • java.lang.annotation.Inherited
  • java.lang.annotation.Repeatable
  • java.lang.annotation.Native

通过@符号加注解名称连起来使用,如@Retention,@Target等

@Retention

@Retention 是保留的意思,用于设置注解的生命周期。其值是 java.lang.RetentionPolicy 枚举类。

  • RetentionPolicy.SOURCE : 只在源代码级别保留有用,在编译时就丢弃了
  • RetentionPolicy.CLASS : 在编译时保留有效,在运行时(JVM中)开始丢弃;这是默认的生命周期
  • RetentionPolicy.RUNTIME : 在编译时、运行时都保留有效,所以可以在反射中使用

生命周期长度是 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码,就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

使用如下,自定义的注解上添加注解产生的时间限制:

@Retention(RetentionPolicy.RUNTIME)
public @interface Test(){
   ... ...
}

@Target

@Target 以数组形式标明注解使用的约束应用上下文,用来表示注解作用范围,超过这个作用范围,编译的时候就会报错,并且可以标记在多个范围中,值由 java.lang.annotation.ElementType 指定。

java.lang.annotation.ElementType 的可用值如下:

  • TYPE : 类、接口、注解、枚举的声明中
  • FIELD : 成员变量,包含枚举的常量的声明中
  • METHOD : 方法的声明中
  • PARAMETER : 正式的参数的声明中
  • CONSTRUCTOR : 构造器的声明中
  • LOCAL_VARIABLE : 局部变量的声明中
  • ANNOTATION_TYPE : 注解类型的声明中
  • PACKAGE : 包的声明中
  • TYPE_PARAMETER : 类型参数的声明中(since JDK8)
  • TYPE_USE : 类型的使用(since JDK8)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Test(){
    ... ...
}

@Documented

@Documented 表明注解的类型将会包含到Javadoc中去,只是用来标识。

@Documented
public @interface Test(){
   ... ...
}

@Inherited

@Inherited 继承的意思,如果标记了该注解的注解,在子项没有其他注解标注时,子项会自动继承父项的该注解

注:子类继承了父类(由于继承特性,子类会拥有父类的公有一切),在通过反射获取子类所有公有字段/方法/构造器的时候,会获取得到自身和父亲的所有public字段/方法/构造器,而通过反射获取所有任何字段/方法/构造器的时候,只能得到自身的所有任何访问权限修饰符的字段/方法/构造器,不会得到父类的任何字段/方法/构造器。然注解不一样,只有当父类的注解中用@Inherited修饰,子类的getAnnotations()才能获取得到父亲的注解以及自身的注解,而getDeclaredAnnotations()只会获取自身的注解,无论如何都不会获取父亲的注解。

@Inherited
public @interface Marks(){}

//父项
@Marks
public class superTest(){}

//子项
public class childTest extends superTest(){}
//此时相当于
@Marks
public class childTest extends superTest(){}

@Repeatable

@Repeatable是jdk8中新增的注解,在没有@Repeatable注解的的注解中,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解

//先创建个基础注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BaceTest(){
  String value() default "value";
}

//开始创建数组形式的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    BaceTest[] value();
}

//使用
@Test("今天天气真好")
@Test("晚上去撸串吧")
public string test(){
 ... ...
}

2.2 Java内置注解

  • @FunctionalInterface : 函数式接口:一个具有一个方法的普通接口。

  • @Override : 实现类要重写父类或者接口的方法

  • @SafeVarargs : 参数安全类型注解,告诉开发者不要用参数做一些不安全的操作

  • @SuppressWarnings : 阻止编译器发出告警,比如调用了使用了 @Deprecated 标记的方法编译器会发出警告,可以使用 @SuppressWarnings 压制警告

    • all : @SuppressWarnings("all") ,会阻止所有的警告
    • cast : 阻止类造型转换警告
    • deprecation : 阻止废弃的警告,比如可能使用了 @Deprecated
    • divzero : 阻止除数为0的警告
    • unchecked : 阻止没有指定泛型的集合表达式
    • fallthrough : 阻止 switch警告,比如某个case没有break语句
    • serial : 阻止实现 Serializable 接口但是没有声明 serialVersionUID 属性的警告
    • finally :阻止没有正确使用finally的警告,比如没有捕获异常,编译器会发出警告
  • @Deprecated : 表示废弃,在编译时会发出警告

2.3 注解与反射结合使用

  • 可以通过 java.lang.reflect.Class 的 isAnnotationPresent() 得知是否存在注解。
  • 可以通过 <T extends Annotation> T getAnnotation(Class<T> annotationClass) 方法获取注解对象
  • 可以通过 Annotation[] getAnnotations() 方法获取注解列表
  • 可以通过Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象。
  • 当一个class被加载,或当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象

     反射是一个动态的机制,允许我们通过字符串来指挥程序实例化,操作属性、调用方法。使得代码提高了灵活性,但是同时也带来了更多的资源开销。加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。

    如果我们需要获取类上的注解,只需要获取到类对象,然后.getDeclaredAnnotation()即可。  

    @Test
    public void testValue() {
        Method[] methods = Test.class.getMethods();
        for (Method method : methods){
            if (method.getName().equals("testName")) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                System.out.println(annotations.length);
                System.out.println(method.getName() + " = " + Arrays.toString(annotations));
            }
        }
    }

2.4 补充知识点

1.注解只有变量(属性),没有方法, 注解的属性是以无参方法的形式声明的。

2.属性后面使用 default 关键字可以给属性设置默认值

public @interface Test {
  //属性
 String name() default '张小明';
}



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。