Java注解,元注解,自定义注解的使用

简介: 本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。

Java注解

从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息

注解(Annotation)可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数与值

基本的注解

java提供了5个基本的注解,分别是@Override,@Deprecated,@SuppressWarnings,@SafeVarargs,@FunctionalInterface

1.@Override

限定父类重写方法: @Override,当子类重写父类方法时,子类可以加上这个注解,当子类重写父类方法时,子类可以加上这个注解。

2.@Deprecated

标示已过时:@Deprecated,这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告(xxx )

3.@SuppressWarnings

抑制编译器警告:@SuppressWarnings,被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告

4.@SafeVarargs

“堆污染”警告与@SafeVarargs

5.@FunctionalInterface

函数式接口与@Functionallnterface,这个注解保证这个接口只有一个抽象方法,注意这个只能修饰接口。

函数式接口:如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法)
接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。
接口里面不能有私有的方法或变量。

Java提供的元注解

元注解的作用就是负责注解其他的注解,用来提供对其他annotation类型作说明。

1.@Retention

@Retention用来修饰注解定义的,作用是被修饰的注解可以保存多久(即注解的生命周期)这个注解需要使用参数(参数可选 SOURCE,CLASS,RUNTIME)。

@Retention 源码:

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
   
    RetentionPolicy value();
}

@Retention注解参数是一个枚举类型,如下

package java.lang.annotation;

public enum RetentionPolicy {
   
    SOURCE,
    CLASS,
    RUNTIME
}

RetentionPolicy.CLASS(默认值) 编译器把该注解记录在class文件中。当运行java程序时,JVM不可获取注解信息。

RetentionPolicy.RUNTIME编译器把该注解记录在class文件中。当运行java程序时,JVM可获取注解信息,程序可通过反射获取该注解信息

RetentionPolicy.SOURCE 该注解只保存在源代码中,编译器直接丢弃该注解。

2.@Target

@Target注解,用于描述注解的使用范围,即注解可以用在哪些地方(TYPE 类|接口,FIELD 字段,METHOD 方法,PARAMETER 参数…),它的使用范围也是一个枚举数组 ElementType[] value();.

@Target注解定义源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
   
    ElementType[] value();
}

@Target注解的 ElementType[]参数数组源码:

package java.lang.annotation;

public enum ElementType {
   
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,
    TYPE_PARAMETER,
    TYPE_USE
}
取值 注解使用范围
METHOD 可用于方法上
TYPE 可用于类或者接口上
ANNOTATION_TYPE 可用于注解类型上(被@interface修饰的类型)
CONSTRUCTOR 可用于构造方法上
FIELD 可用于字段上
LOCAL_VARIABLE 可用于局部变量上
PACKAGE 用于记录java文件的package信息
PARAMETER 可用于参数上

3.@Documented

@Documented注解用于指定被修饰的注解类将被javadoc工具提取成文档,如果定义注解类时使用了这个注解修饰,则所有使用该注解修饰的程序员苏API文档将会包含该注解说明。

package java.lang.annotation;

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

4.@Inherited

@Inherited注解指定被它修饰的注解将具有继承性,即子类可以继承父类中的该注解

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
   
}

自定义注解

自定义注解,需要使用@interface来定义,使用@interface自定义注解时,自动继承java.lang.annotation.Annotation接口

自定义注解格式:

权限修饰符 @interface 注解名{
   
    // 定义内容
    String value() default "";
    // 参数类型 参数名 默认值 ;
    .....
}
  • @interface 用来声明一个注解
  • 其中上面的 String value();表示这个注解需要提供一个String类型的参数,且其默认值为空字符串default ""
  • value() 就是参数的名称
  • String 就是参数的要求类型,参数类型只能是基本类型(Class,String,enum)
  • 可以通过default 来声明参数的默认值
  • 如果只有一个参数成员,则一般参数名为value(当然可以自定义参数名,只是一种习惯)
  • 注解元素必须要求有值,定义注解元素时,经常使用空字符串,0作为默认值

自定义注解的使用

package com.robin.annotation;

import java.lang.annotation.*;
import java.lang.reflect.Method;

// 使用自定义的注解 传入参数 robin 和 23
@MyAnnotation(value = "robin", age = 23)
public class AnnoTest01 {
   


    // 使用自定义的注解 传入参数 知更鸟 和 18
    @MyAnnotation(value = "知更鸟",age = 18)
    public void test01() {
   

    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
   
        // 通过反射来获取当前Class类对象中的注解
        Class<?> cls = Class.forName("com.robin.annotation.AnnoTest01");// 获取AnnoTest01的Class类对象
        MyAnnotation annotation1 = cls.getAnnotation(MyAnnotation.class);// 获取当前Class类对象的注解信息
        System.out.println("作用在类上的注解:"+annotation1);// @com.robin.annotation.MyAnnotation(value=robin, age=23)
        // 通过Class类对象获取Method对象
        Method test01 = cls.getMethod("test01");
        MyAnnotation annotation2 = test01.getAnnotation(MyAnnotation.class);
        System.out.println("作用在method上的注解:"+annotation2);// @com.robin.annotation.MyAnnotation(value=知更鸟, age=18)

    }

}

// 自定义内部类注解
@Target({
   ElementType.TYPE, ElementType.METHOD})// 作用范围为类和方法上面
@Retention(RetentionPolicy.RUNTIME)// 此注解的生命周期为RUNTIME
@interface MyAnnotation {
   
    String value() default "";

    int age() default 0;
}

在这里插入图片描述


相关文章
|
3月前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
98 1
|
2月前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
74 7
|
3月前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
58 1
|
2月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
107 34
|
2月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
103 5
|
3月前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
96 14
|
3月前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
51 0
|
27天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
85 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
23天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题