前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java进阶-注解

Java进阶-注解

作者头像
reload
发布2024-03-08 09:41:37
1530
发布2024-03-08 09:41:37
举报
文章被收录于专栏:Java后端

注解(Annotation)是Java 5 版本之后可以在源代码中嵌入的一种补充信息,是 Java 平台中非常重要的一部分。这次的内容如下

一、注解概述

注解本质上都是一种数据类型,是一种接口类型。到 Java 8 为止 Java SE 提供了 11 个内置注解( 5 个是基本注解,来自于 java.lang 包。 6 个是元注解,它们来自于 java.lang.annotation 包)

注:自定义注解会用到元注解(负责注解其他的注解)。

1、相关说明

1)注解都是 @ 符号开头的,如重写 @Override 注解。 2)同 Class 和 Interface 一样,注解也属于一种类型。 3)默认情况下,注解可以在程序的任何地方使用,通常用于修饰类、接口、方法和变量等。 4)注解并不能改变程序的运行结果,也不会影响程序运行的性能(有些注解可以在编译时给用户提示或警告,有的注解可以在运行时读写字节码文件信息) 5)注解可以元数据这个词描述(即一种描述数据的数据),因此可以说注解就是源代码的元数据。

2、注解作用
代码语言:javascript
复制
1.生成帮助文档。这是最常见的,也是 Java 最早提供的注解。常用的有 @see、@param 和 @return 等;
2.跟踪代码依赖性,实现替代配置文件功能。比较常见的是 Spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量;
3.在编译时进行格式检查。如把 @Override 注解放在方法前,如果这个方法并不是重写了父类方法,则编译时就能检查出。

二、注解类型

1、基本注解(5个)
1.1 @Override

用来指定方法重写的,只能修饰方法并且只能用于方法重写,不能修饰其它的元素。它可以强制一个子类必须重写父类方法或者实现接口的方法。

1.2 @Deprecated

用来注解类、接口、成员方法和成员变量等,用于表示某个元素(类、方法等)已过时。当其他程序使用已过时的元素时,编译器将会给出警告。

1.3 @SuppressWarnings

指示被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告,且会一直作用于该程序元素的所有子元素。抑制警告的关键字有很多,有兴趣的可自行去搜索查看。 1)抑制单类型的警告

@SuppressWarnings(“unchecked”)

2)抑制多类型的警告

@SuppressWarnings(“unchecked”,“rawtypes”)

3)抑制所有类型的警告

@SuppressWarnings(“unchecked”)

1.4 @SafeVarargs

可用来抑制编译器警告

注:@SafeVarargs注解不适用于非 static 或非 final 声明的方法,对于未声明为 static 或 final 的方法,如果要抑制 unchecked 警告,可以使用 @SuppressWarnings 注解。

1.5 @FunctionalInterface

用来指定某个接口必须是函数式接口,且@FunInterface 只能修饰接口,不能修饰其它程序元素。

注:函数式接口是为 Java 8 的 Lambda 表达式准备的,Java 8 允许使用 Lambda 表达式创建函数式接口的实例,因此 Java 8 专门增加了 @FunctionalInterface。

1.6 基本注解示例

1)@Override注解

代码语言:javascript
复制
public class AnnotationDemo {
    private String name="";
    private int age;
    //...
    //@Override注解: 告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法,否则就会编译出错。
    @Override
    public String t0String(){ // toString写错,@Override下面会有红色波浪线提示(Method does not override method from its superclass)
        return "Person [name="+name+",age="+age+"]";
    }
}

2)@Deprecated注解 先创建一个Person类

代码语言:javascript
复制
@Deprecated
public class Person {
    @Deprecated
    protected String name;
    private  int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Deprecated
    public void setNameAndAge(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    public String toString(){
        return "Person[name"+name+",age="+age+"]";
    }
}

再创建测试类

注:由于类 Person、成员变量 name 和setNameAndAge 方法被 @Deprecated 注解,这些被注解的 API 都会被画上删除线。调用这些 API 代码也会有删除线。

Java 9 @Deprecated 注解新增属性:

代码语言:javascript
复制
forRemoval:指定该 API 在将来是否会被删除。
since:指定该 API 从哪个版本被标记为过时。

如下

代码语言:javascript
复制
class Test {
    // since属性指定从哪个版本开始被标记成过时,forRemoval指定该API将来会被删除
    @Deprecated(since = "9", forRemoval = true)
    public void print() {
        System.out.println("你好,李四!");
    }
}
public class DeprecatedTest {
    public static void main(String[] args) {
        // 下面使用info()方法时将会被编译器警告
        new Test().print();
    }
}

3)@SuppressWarnings 注解 调用2)中的Person类创建如下测试类,由于使用了@Deprecated注解表示API已经过时了,所以会产生删除线警告,但这里因为使用了 @SuppressWarnings 注解,就没有警告了(取消了警告)

代码语言:javascript
复制
public class PersonTest {
    @SuppressWarnings({ "deprecation" })
    public static void main(String[] args) {
        Person p = new Person();
        p.setNameAndAge("zhangsan",22);
        p.name="lishi";
    }
}

4)@SafeVarargs 注解

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        // 传递可变参数,参数是泛型集合
        display(10, 20, 30);
        // 传递可变参数,参数是非泛型集合
        display("10", 20, 30); // 会有编译警告
    }
    public static <T> void display(T... array) { // 可变参数形式:方法名(类型...数组名)
    //方法display()提示Annotate as '@SafeVararg'(即要在上一行添加@SafeVararg注解)
        for (T arg : array) {
            System.out.println(arg.getClass().getName() + ":" + arg);
        }
    }
}

运行结果

代码语言:javascript
复制
java.lang.Integer:10
java.lang.Integer:20
java.lang.Integer:30
java.lang.String:10
java.lang.Integer:20
java.lang.Integer:30

5)@FunctionalInterface注解

代码语言:javascript
复制
// 使用@FunctionalInterface修饰函数式接口。
public interface FunInterface {
    static void print() { // 静态方法
        System.out.println("我的个人网站:https://zhengyquan.gitee.io/");
    }
    default void show() {
        System.out.println("我的腾讯云社区首页:https://cloud.tencent.com/developer/user/10491946");
    }
    void test(); // 只定义一个抽象方法
}
// @FunctionalInterface 注解的作用只是告诉编译器检查这个接口,保证该接口只能包含一个抽象方法,否则就会编译出错。

注:@FunctionalInterface 注解主要是帮助程序员避免一些低级错误,例如,在上面的 FunInterface 接口中再增加一个抽象方法 abc(),编译程序时将出现如下错误提示:“@FunctionInterface”批注无效;FunInterface不是functional接口。

2、元注解(6个)

元注解负责对其它注解进行说明的注解,自定义注解时可以使用元注解

2.1 @Documented

@Documented 是一个标记注解,没有成员变量。用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。

默认情况下,JavaDoc 是不包括注解的,但如果声明注解时指定了 @Documented,就会被 JavaDoc 之类的工具处理,所以注解类型信息就会被包括在生成的帮助文档中。

2.2 @Target

用来指定一个注解的使用范围,即被 @Target 修饰的注解可以用在什么地方。@Target 注解有一个成员变量(value)用来设置适用目标,value 是 java.lang.annotation.ElementType 枚举类型的数组, ElementType 常用的枚举常量。

2.3 @Retention

@Retention 用于描述注解的生命周期,也就是该注解被保留的时间长短。@Retention 注解中的成员变量(value)用来设置保留策略,value 是 java.lang.annotation.RetentionPolicy 枚举类型,RetentionPolicy 有 3 个枚举常量。如下

SOURCE:在源文件中有效(即源文件保留)

CLASS:在 class 文件中有效(即 class 保留)

RUNTIME:在运行时有效(即运行时保留)

2.4 @Inherited

@Inherited 是一个标记注解,用来指定该注解可以被继承。使用 @Inherited 注解的 Class 类,表示这个注解可以被用于该 Class 类的子类。

注:如果某个类使用了被 @Inherited 修饰的注解,则其子类将自动具有该注解。

2.5 @Repeatable

@Repeatable 注解是 Java 8 新增加的,允许在相同的程序元素中重复注解,需要对同一种注解多次使用时,往往需要借助 @Repeatable 注解

了解:Java 8 版本以前,同一个程序元素前最多只能有一个相同类型的注解,如果需要在同一个元素前使用多个相同类型的注解,则必须使用注解“容器”。

2.6 @Native

使用 @Native 注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。@Native 注解不常使用,了解即可。

3、自定义注解
3.1 声明

@interface 关键字实现,与定义接口非常类似,如

代码语言:javascript
复制
public @interface Test {}
3.2 几点注意

定义注解和定义类相似,注解前面的访问修饰符和类一样有两种,分别是公有访问权限(public)和默认访问权限(默认不写)。

一个源程序文件中可以声明多个注解,但只能有一个是公有访问权限的注解(同定义类,只能有一个public修饰的类,其他类可以有多个)。且源程序文件命名和公有访问权限的注解名一致(同定义类,源文件名和类名相同)

3.3 根据注解是否包含成员变量进行分类
代码语言:javascript
复制
1.标记注解:没有定义成员变量的注解类型(仅利用自身的存在与否来提供信息)
2.元数据注解:包含成员变量的注解,由于可以接受更多的元数据,也被称为元数据注解。

示例 1)不包含任何成员变量的注解称为标记注解

代码语言:javascript
复制
// 定义一个标记注解
public @interface Test {
}

2)注解中可以定义成员变量

代码语言:javascript
复制
public @interface MyTag {
    // 定义带两个成员变量的注解
    // 注解中的成员变量以方法的形式来定义
    String name();
    int age();
    // 成员变量也可以有访问权限修饰符,但是只能有公有权限和默认权限。
}

3)如果在注解里定义了成员变量,就需要为成员变量赋值

代码语言:javascript
复制
public class Test {
    // 使用带成员变量的注解时,需要为成员变量赋值
    @MyTag(name="xx", age=6)
    public void info() {
        ...
    }
    ...
}

4)注解中的成员变量也可以有默认值,可使用 default 关键字

代码语言:javascript
复制
public @interface MyTag {
    // 定义了两个成员变量的注解
    // 使用default为两个成员变量指定初始值
    String name() default "李四";
    int age() default 18;
}

5)如果为注解的成员变量指定了默认值,则使用该注解时直接使用默认值。

也可在使用 MyTag 注解时为成员变量指定值,指定后默认值不起作用

代码语言:javascript
复制
public class Test {
    // 使用带成员变量的注解
    // MyTag注释的成员变量有默认值,所以可以不为它的成员变量赋值
    @MyTag
    public void info() {
        ...
    }
    ...
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、注解概述
    • 1、相关说明
      • 2、注解作用
      • 二、注解类型
        • 1、基本注解(5个)
          • 1.1 @Override
          • 1.2 @Deprecated
          • 1.3 @SuppressWarnings
          • 1.4 @SafeVarargs
          • 1.5 @FunctionalInterface
          • 1.6 基本注解示例
        • 2、元注解(6个)
          • 2.1 @Documented
          • 2.2 @Target
          • 2.3 @Retention
          • 2.4 @Inherited
          • 2.5 @Repeatable
          • 2.6 @Native
        • 3、自定义注解
          • 3.1 声明
          • 3.2 几点注意
          • 3.3 根据注解是否包含成员变量进行分类
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档