Java 注解

前言

1、注解

  • Java 语言中的类、方法、变量、参数和包等都可以被标注。

  • 和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。

  • Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容。

  • 当然它也支持自定义 Java 标注。

  • 注解分类

    • 按照注解的作用域(@Retention)分

      • RetentionPolicy.SOURCE: Java 源文件上的注解
      • RetentionPolicy.CLASS: Class 类文件上的注解
      • RetentionPolicy.RUNTIME: 运行时的注解
    • 按照注解的来源分

      • 内置注解,如 @Override@Deprecated 等等
      • 第三方注解,如 Hibernate, Struts, Spring 等等
      • 自定义注解,如仿 Hibernate 的自定义注解

2、基本内置注解

关键字 介绍 示例代码
@Override 用在方法上,表示这个方法重写了父类的方法。如果父类没有这个方法,那么就无法编译通过。
@Deprecated 表示这个方法已经过期,不建议开发者使用。暗示在将来某个不确定的版本,就有可能会取消掉。
@SuppressWarnings 忽略警告信息。
常见的值,分别对应如下意思:
       1. deprecation:使用了不赞成使用的类或方法时的警告(使用 @Deprecated 使得编译器产生的警告);
       2. unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合
           保存的类型; 关闭编译器警告;
       3. fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
       4. path:在类路径、源文件路径等中有不存在的路径时的警告;
       5. serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
       6. finally:任何 finally 子句不能正常完成时的警告;
       7. rawtypes:泛型类型未指明;
       8. unused:引用定义了,但是没有被使用;
       9. all:关于以上所有情况的警告。
@SuppressWarnings({"rawtypes", "unused"})
@SafeVarargs 当使用可变数量的参数的时候,而参数的类型又是泛型 T 的话,就会出现警告。这个时候使用来去掉这个警告。
@SafeVarargs 注解只能用在参数长度可变的方法或构造方法上,且方法必须声明为 static 或 final,否则会出现编译错误。
一个方法使用 @SafeVarargs 注解的前提是,必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。
@FunctionalInterface 用于约定函数式接口。
  • 函数式接口

    • 如果接口中只有一个抽象方法(可以包含多个默认方法或多个 static 方法),该接口称为函数式接口。
    • 函数式接口其存在的意义,主要是配合 Lambda 表达式 来使用。
  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Override                                               // 重写父类方法
    public String toString() {
    return name;
    }

    @Deprecated // 方法已经过期
    public void hackMap() {

    }

    @SuppressWarnings({ "rawtypes", "unused" }) // 忽略 引用定义了,但是没有被使用 警告信息
    public static void main(String[] args) {
    List heros = new ArrayList();
    }

    @SafeVarargs // 使用可变数量,而参数的类型又是泛型 T
    public static <T> T getFirstOne(T... elements) {
    return elements.length > 0 ? elements[0] : null;
    }

    @FunctionalInterface // 约定函数式接口
    public interface AD {
    public void adAttack();
    }

3、自定义注解

  • 创建注解类型的时候即不使用 class 也不使用 interface,而是使用 @interface

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.ElementType.TYPE;

    import java.lang.annotation.Documented;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    @Target({METHOD, TYPE}) // 表示这个注解可以用用在类/接口上,还可以用在方法上
    @Retention(RetentionPolicy.RUNTIME) // 表示这是一个运行时注解,即运行起来之后,才获取注解中的相关信息
    @Inherited // 表示这个注解可以被子类继承
    @Documented // 表示当执行 javadoc 的时候,本注解会生成相关文档
    public @interface JDBCConfig { // @interface
    String ip(); // 注解元素,这些注解元素就用于存放注解信息,在解析的时候获取出来
    int port() default 3306;
    String database();
    String encoding();
    String loginName();
    String password();
    }
  • 使用自定义的注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @JDBCConfig(ip = "127.0.0.1",                           // 使用自定义的注解
    database = "test",
    encoding = "UTF-8",
    loginName = "root",
    password = "admin")
    public class DBUtil {
    static {
    try {
    Class.forName("com.mysql.jdbc.Driver");
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }
    }
    }
  • 解析自定义的注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;

    import anno.JDBCConfig;

    @JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
    public class DBUtil {
    static {
    try {
    Class.forName("com.mysql.jdbc.Driver");
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }
    }

    public static Connection getConnection() throws SQLException, NoSuchMethodException, SecurityException {

    // 通过反射,获取这个 DBUtil 这个类上的注解对象,拿到注解对象之后,通过其方法,获取各个注解元素的值
    JDBCConfig config = DBUtil.class.getAnnotation(JDBCConfig.class);

    String ip = config.ip();
    int port = config.port();
    String database = config.database();
    String encoding = config.encoding();
    String loginName = config.loginName();
    String password = config.password();

    String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
    return DriverManager.getConnection(url, loginName, password);
    }
    }

4、元注解

  • 元数据 metadata 是为其他数据提供信息的数据。

  • 元注解 meta annotation 是用于注解 自定义注解 的注解。

关键字 介绍 示例代码
@Target 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上。
可以选择的位置列表如下:
           ElementType.TYPE:能修饰类、接口或枚举类型
           ElementType.FIELD:能修饰成员变量
           ElementType.METHOD:能修饰方法
           ElementType.PARAMETER:能修饰参数
           ElementType.CONSTRUCTOR:能修饰构造器
           ElementType.LOCAL_VARIABLE:能修饰局部变量
           ElementType.ANNOTATION_TYPE:能修饰注解
           ElementType.PACKAGE:能修饰包
@Target({METHOD, TYPE})
@Retention 表示生命周期。
可选的值有 3 个:
           RetentionPolicy.SOURCE:注解只在源代码中存在,编译成 class 之后,就没了。@Override 就是这种注解。
           RetentionPolicy.CLASS: 注解在 java 文件编程成 .class 文件后,依然存在,但是运行起来后就没了。
                               @Retention 的默认值,即当没有显式指定 @Retention 的时候,就会是这种类型。
           RetentionPolicy.RUNTIME:注解在运行起来之后依然存在,程序可以通过反射获取这些信息,自定义注解
                               @JDBCConfig 就是这样。
@Retention(RetentionPolicy.RUNTIME)
@Inherited 表示这个注解可以被子类继承。 @Inherited
@Documented 表示当执行 javadoc 命令生成 API 文档的时候,本注解会生成相关文档。 @Documented
@Repeatable 当没有 @Repeatable 修饰的时候,注解在同一个位置,只能出现一次。
使用 @Repeatable 之后,再配合一些其他动作,就可以在同一个地方使用多次了。
java1.8 新增。
@Repeatable(FileTypes.class)
public @interface FileType { };

5、仿 Hibernate 注解

文章目录
  1. 1. 前言
  2. 2. 1、注解
  3. 3. 2、基本内置注解
  4. 4. 3、自定义注解
  5. 5. 4、元注解
  6. 6. 5、仿 Hibernate 注解
隐藏目录