JavaSE 注解

19 注解

19.1 注解概述

注解,或者叫注释

注释Annotation是一种引用数据类型,编译之后也是xxx.class文件

怎么自定义注解呢?语法格式?

修饰符列表@interface 注解类型名{}

注解怎么使用?用在哪里

注解使用:@注解类姓名,可以使用在类上,属性上,方法上,变量上等...,注解还可以出现在注解类型上

  1. 代码实现

新建Annotation定义注解

java 复制代码
package com.bjpowernode._15Annotation;
/*
自定义注解
 */
public @interface MyAnnotation00 {
}

在类上,属性上,方法上,变量,接口,枚举上等...,

java 复制代码
package com.bjpowernode._15Annotation;

/**
 1.注解,或者叫注释
 2.注释Annotation是一种引用数据类型,编译之后也是xxx.class文件
 3.怎么自定义注解呢?语法格式?
    [修饰符列表]@interface 注解类型名{}
 */

@MyAnnotation00
public class AnnotationTest01 {
    @MyAnnotation00
    private int no;
    @MyAnnotation00
    public AnnotationTest01(){}
    @MyAnnotation00
    public  static  void m1(){
        int i =100;
    }
    @MyAnnotation00
    public void m2(){

    }

}
@MyAnnotation00
interface MyInterface{

}
@MyAnnotation00
enum Season {
    SPRING,SUMMER,AUTUMN,WINTER
}

甚至注解用在注解上面

java 复制代码
package com.bjpowernode._15Annotation;
@MyAnnotation00
public @interface OtherAnnotation {
    
}

19.2 JDK自带的注解

19.2.1 种类

java.lang包下

Deprecated:这个注解表示被标记的元素已"过时"。它的主要目的是在不破坏现有代码的前提下,为开发者提供一个过渡期,表明存在更好的替代方案,并警示新代码不要继续使用

Override:被注解的方法旨在重写(或实现)其父类(或接口)中声明的方法

SupressWarnings(了解):在注解的元素(及该元素包含的所有程序元素)中,应取消显示指定的编译器警告

元注解:见下

19.2.2 Override注解

java 复制代码
package com.bjpowernode._15Annotation;
/*
关于JDK lang包下的Override注解:
public @interface Override{
}
 */

//@Override 编译报错
public class AnnotationTest02 {
    //@Override 编译报错
    private  int no;
    //@Override是标识性注解,只能出现在方法上,是给编译器参考的,和运行阶段没有关系
    //凡是java中的方法有这个注释的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器会报错
        //例如下面的toString()方法写错了,携程ToString,@Override就会检查此方法有没有错误,认为他没有重写报错
    @Override
    public String toString() {
        return super.toString();
    }
    public static void main(String[] args) {
    }
}

19.2.3 元注解

  • 概念

就是注解的注解

@Override为什么不能出现在类或者其他上面

因为源码上面有一行注解@Target(ElementType.METHOD),表示只能出现在方法上,这个就是元注解

@Retention(RetentionPolicy.SOURCE)表示@Override保存在源文件当中,而不是在AnnotationTest02注解文件当中

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  • 常见元注解:TargetRetention

Target:用来标注"注解类型"的"注解",这个Target注解用来标注"被标注的注解"可以出现在哪一些位置上

Retention:用来标注"注解类型"的"注解",用来标注"被标注的注解"可以出现在哪些位置上。例如@Retention(RetentionPolicy.SOURCE)表示该注解只被保留在java源文件中,编译后生成class就没了

@Retention(RetentionPolicy.CLASS)表示该注解被保存在class文件中

@Retention(RetentionPolicy.RUNTIME)表示该注解被保存在class当中,并且可以被反射机制所读取

19.2.4 Deprecated

  • 注解源码
java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

@Retention(RetentionPolicy.RUNTIME)表示注解已经保存在字节码文件中了, 并且可以被程序所读到

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})既可以在构造器,属性,变量,方法,包上,参数上,类上都可以出现

  • 代码实现
java 复制代码
package com.bjpowernode._15Annotation;

@Deprecated//表示这个类已经过时了
public class AnnotationTest03 {
    public static void main(String[] args) {
        AnnotationTest03.doSome1();
        AnnotationTest03 at = new AnnotationTest03();
        at.doOther();
    }
    //Deprecated这个注解标注的元素已过时
    //主要是向其他程序原传递一个信息,已过时,有更好的解决方案存在
    @Deprecated
    public static void doSome1(){
        System.out.println("do something!");

    }
    @Deprecated
    public  void doSome2(){
        System.out.println("do something!");

    }


    @Deprecated
    public static void doOther(){
        System.out.println("do other...");

    }
}

class T {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        AnnotationTest03 at1 = new AnnotationTest03();
        //这个会出现------,表示@Deprecated的信息是保留在注解已经保存在字节码文件中了, 并且可以被程序所读到
        at1.doSome2();//在下面Problems会出现警告:'doSome2()' is deprecated

        Class c = Class.forName("java.lang.Date");
        Object obj = c.newInstance();

    }
}

19.3 实现自定义注解

19.3.1 自定义注解指定属性以及使用自定义有属性的注解

自定义注解

java 复制代码
package com.bjpowernode._15Annotation;

public @interface MyAnnotion02 {
    /**
     * 我们通常在注解中可以定义属性,以下这个是MyAnnotation的name属性
     * 看着像1个方法,但是是属性name
     * @return
     */
    String name();
    String color();

    int age() default 29;//默认值29
}

java类使用自定义注解

java 复制代码
package com.bjpowernode._15Annotation;

@Deprecated()//可以不指定值,因为在新的jdk9中,使用deflaut制定了since的默认值
public class Annotation04 {
    //@MyAnnotion02():编译报错的原因,如果一个注解当中有属性,那么必须给属性赋值
    //指定name属性的值就好了
    @MyAnnotion02(name="zhangsan",color= "红色")//age默认值设置好了,可以不用写
    public void doSome(){
    }
}

19.3.2 自定义注解运用在方法上

  1. 注解属性名称省略(仅限属性名是value的时候并且只有一个属性)
  • 注解类
java 复制代码
package com.bjpowernode._15Annotation;

public @interface OtherAnnotation04 {
    String name();
}
  • 类运用自定义注解
java 复制代码
package com.bjpowernode._15Annotation;

public class AnnotationTest05 {
    @MyAnnotation03(value="hehe")
    public void doSome(){

    }
    @MyAnnotation03("haha")///注解属性名称省略(仅限属性名是value的时候并且只有一个属性)
    public void doOther(){

    }
}
  1. 注解属性名称不可省略
  • 注解类
java 复制代码
package com.bjpowernode._15Annotation;

public @interface OtherAnnotation04 {
    String name();
}
  • 类运用自定义注解
java 复制代码
package com.bjpowernode._15Annotation;

public class OtherAnnotationTest06 {
    @OtherAnnotation04("test")
    public void doSome(){
    }
}

19.3.3 属性的注解类型

  1. 可以是什么类型
JAVA 复制代码
package com.bjpowernode._15Annotation;

public @interface MyAnnotation05 {
    /*
    注解当中的属性可以是什么类型?
    可以是byte short int long float double boolean char String Class 枚举类
    以及以上每一种数据形式

     */

    int value1();
    String value2();
    int[] value3();
    String[] value4();
    Season value5();//自建的枚举类型
    Season[] value6();//枚举数组
    Class parameterType();//ClASS类
    Class[] parameters();//CLASS数组
}

枚举类

java 复制代码
package com.bjpowernode._15Annotation;

public enum Season07 {
    SPRING,SUMMER,AUTUMN,WINTER
}
  1. 数组只有一个可以省略大括号的注解
  • 注解
java 复制代码
package com.bjpowernode._15Annotation;

public @interface OtherAnnotation05 {
    int age();
    /*
    邮箱地址属性,支持多个
     */
    String[] email();

    /**
     * 季节数组,Season是枚举类型
     * @return
     */
    Season[] seasonArray();
}
  • 类使用自定义注解
java 复制代码
package com.bjpowernode._15Annotation;

public class OtherAnnotationTest08 {
    @OtherAnnotation05(age=25,email={"zhangsan@123.com","zhangsan@souhu.com"},
                        seasonArray={Season.SPRING,Season.SUMMER})
    public void doSome(){

    }

	//数据只有一个,可以省略大括号
    @OtherAnnotation05(age=25,email="zhangsan@123.com",seasonArray=Season.SPRING)
    public void doOther(){
    }
}

19.3.4 @Retention源码

因此@Retention(RetentionPolicy.RUNTIME)其实就是@Retention(value=RetentionPolicy.RUNTIME),并且RetentionPolicy是一个枚举类

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
java 复制代码
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

19.3.5 @Target源码

因此@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})的意思是传入一个 ElementType\[\]枚举的数组

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
java 复制代码
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

来个运用

  • 注解
java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//只允许该注解可以标注类,方法,value=可以省略
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//希望注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation06 {

}
  • 使用自定义注解的类
java 复制代码
package com.bjpowernode._15Annotation;

public class MyAnnotationTest09 {
    //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to field,因为自定义的注解只能在类和方法上,
    // 不能在属性上,如果想要加上ElementType.FIELD
    int i;
    //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to constructor不能出现在构造方法上
    public MyAnnotationTest09(){
    }
    @MyAnnotation06
    public void doSome(){
        //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to local variable不能出现在局部变量上
        int i;
    }
}

19.4 反射注解

  1. 反射机制代码实现获取类的注解
  • 注解
java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//只允许该注解可以标注类,方法,value=可以省略
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//希望注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation06 {
    /*
    value属性
     */
    //String value() default "北京大兴区";
    String value();
}
  • 使用注解的类
java 复制代码
package com.bjpowernode._15Annotation;
@MyAnnotation06("上海浦东区")
public class MyAnnotationTest09 {
    //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to field,因为自定义的注解只能在类和方法上,
    // 不能在属性上,如果想要加上ElementType.FIELD
    int i;

    //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to constructor不能出现在构造方法上
    public MyAnnotationTest09(){

    }

//    @MyAnnotation06
    public void doSome(){
        //@MyAnnotation06 报错:'@MyAnnotation06' not applicable to local variable不能出现在局部变量上
        int i;

    }
}
  • 程序入口类通过反射获取注解
java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.annotation.Annotation;

public class RefletAnnotationTest10 {
    public static void main(String[] args) throws ClassNotFoundException {
        //先获取类
        Class c = Class.forName("com.bjpowernode._15Annotation.MyAnnotationTest09");

        //判断类上面是否有Annotation注解类型,即是否有MyAnnotation06注解
        System.out.println(c.isAnnotationPresent(MyAnnotation06.class));//true

        //判断String类上是否存在这个注解,是没有我们自定义的这个注解的
        Class stringClass = Class.forName("java.lang.String");
        System.out.println(stringClass.isAnnotationPresent(MyAnnotation06.class));//false

        //如果存在我们想要知道的那个自定义注解
        if(c.isAnnotationPresent(MyAnnotation06.class)){
            //获取该注解对象
            //转型的原因是 getAnnotation 返回的是Annotation类型。如果不转型 不能调用MyA你notation的属性
            MyAnnotation06 myAnnotation = (MyAnnotation06)c.getAnnotation(MyAnnotation06.class);
            System.out.println("类上面的注解对象"+myAnnotation);//类上面的注解对象@com.bjpowernode._15Annotation.MyAnnotation06()

            //获取对象的属性怎么办?跟调接口没区别
            String value = myAnnotation.value();
            System.out.println(value);//北京大兴区 不用默认值写在注解上就输出:上海浦东区
        }
    }
}
  1. 反射机制代码实现获取方法的注解

注解

java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation07 {
    String username();
    String password();
}

使用自定义注解的类

java 复制代码
package com.bjpowernode._15Annotation;

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

public class MyAnnotationTest10 {
    @MyAnnotation07(username = "admin",password = "123")
    public void doSome(){

    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //获取MyAnnotationTest的doSome方法上面的注解信息
        Class c = Class.forName("com.bjpowernode._15Annotation.MyAnnotationTest10");
        //获取方法doSome()方法
        Method doSomeMethod = c.getDeclaredMethod("doSome");
        //判断该方法上是否存在这个注解
        if(doSomeMethod.isAnnotationPresent(MyAnnotation07.class)){
            MyAnnotation07 myAnnotation = (MyAnnotation07)doSomeMethod.getAnnotation(MyAnnotation07.class);
            System.out.println(myAnnotation.username());//admin
            System.out.println(myAnnotation.password());//123
        }
    }
}
  1. 案例

需求:假设有这样一个注解,叫做@id,这个注解只能出现在类上面,当类上有这个注解的时候,要求这个类中必须要有一个int类型的id属性。如果没有这个属性就报异常,如果有这个属性则正常执行

思考注解什么作用?注解当中等同于一个标记,如果元素上有这个注解怎么办,没有这个注解怎么办

注解

java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

User类

java 复制代码
package com.bjpowernode._15Annotation;
@Id09
public class User11 {
    int id;
    String name;
    String password;
}

反射注解类

java 复制代码
package com.bjpowernode._15Annotation;

import java.lang.reflect.Field;

public class AnnotationTest11 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class userClass = Class.forName("com.bjpowernode._15Annotation.User11");
        //判断类上是否含有Id注解
        if(userClass.isAnnotationPresent(Id09.class)){
            //当一个上面有一个Id注解的时候,要求类中必须存在int类型的id属性
            Field[] fields = userClass.getDeclaredFields();
            boolean isOk = false;
            for (Field field : fields) {
                if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
                    //表示类是合法的
                    isOk = true;
                    break;
                }

            }
            //判断是否合法
            if(!isOk){
                throw new HasnotIdPropertyException12("被@Id标注的类中必须要有一个int类型的id属性");
            }

        }

    }
}

异常类

java 复制代码
package com.bjpowernode._15Annotation;

public class HasnotIdPropertyException12 extends RuntimeException{
    public HasnotIdPropertyException12(){
    }
    public HasnotIdPropertyException12(String s){
        super(s);
    }
}
相关推荐
Vallelonga7 小时前
Rust 中的枚举
开发语言·rust
cfm_29147 小时前
Java JVM 零基础入门
java·jvm
兰令水7 小时前
leecodecode【状态机DP】【2026.6.9打卡-java版本】
java·开发语言·算法
我是一颗柠檬7 小时前
【Java项目技术亮点】接口限流熔断:从Sentinel到令牌桶/漏桶,手把手教你构建高可用服务防护体系
java·数据库·sentinel
宸津-代码粉碎机7 小时前
Spring AI企业级实战|Agent长期记忆持久化落地,彻底解决多轮对话上下文丢失问题
java·开发语言·人工智能·后端·python·spring
在放️7 小时前
Python 爬虫 · bs4 模块基础
开发语言·爬虫·python
belong_my_offer7 小时前
Python 数据采集完全指南 —— 从零开始掌握网络爬虫与文件读取
开发语言·爬虫·python
开源推荐官7 小时前
2026 商城系统源码实测,真正适合二开的系统有哪些?
java·架构·开源
云烟成雨TD7 小时前
Spring AI 1.x 系列【58】提示词工程(Prompt Engineering)
java·人工智能·spring
Adorable老犀牛7 小时前
Prometheus 常用告警规则 rules.yml
开发语言·prometheus·exporter·nodeexpoeter