Java基础学习-注解(一篇通俗易懂的JAVA注解入门文章)

注解概念

Annotation是从JDK5.0开始引入的新技术

Annotation的作用:

  • 可以对程序作出解释,这一点和注释comment类似
  • 对程序进行检查和约束,例如@Override
  • 可以被其他程序(比如:编译器等)读取

Annotation的格式:

  • 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarning(value=”unchecked”)

Annotation在哪里使用:

  • 可以附加在package、class、method、field等上面,相等于给他们添加了额外的辅助信息,然后结合反射机制实现对这些元数据的访问
JAVA的内置注解
@Override

定义在java.lang包中,此注解只适用于修饰方法,表示该方法打算重写父类中的同名方法,并且具有检查作用

public class Person {
    public void test () {

    }
}

class Student extends Person {
    @Override
    public void test () {

    }
}
@Deprecated

定义在java.lang包中,此注释可以修饰方法、属性、类,注释@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为它已经过时了,然后存在更好的替代方法,但是你使用也没有任何影响
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hGlzSfcY-1640153209850)(image-20211222140133811.png)]
表示test()方法已经失效。

@SupressWarnings

定义在java.lang包中,用来抑制编译时产生的黄色警告信息,虽然这些警告信息不会影响编译结果,但是看着不舒服,然后该注释和前两个注释有所不同,你需要添加一个参数才能正确使用。

具体参数信息如下所示:

  • @SuppressWarnings(“all”) // 压制所有警告
  • @SuppressWarnings(“unchecked”) // 压制"unchecked"警告
  • @SuppressWarnings(value={“unchecked”, “deprecation”}) // 压制"unchecked", "deprecation"警告

注意:public @interface SuppressWarnings {String[] value();},其中value是参数名,而String[]是参数是类型,当注解只使用value这一个参数的时候,value可以省略,例如上面的@SuppressWarnings(“all”)和@SuppressWarnings(“unchecked”)就是省略了前面的value,但是仅限参数名是value,并且注解中只使用value这一个参数的情况才可以 省略value,下面也会提到。

JAVA中的元注解

什么是元注解?元注解就是对其他普通注解进行说明解释的注解。

java中定义了4个元注解,自动继承了java.lang.annotation.Annotation

@Target

@Target限定了一个注解的使用范围,作用域,默认可以在任何地方使用,也可以指定使用的范围。

以**@Override注解为例,我们打开@Override**注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

点击进入**@Target(ElementType.METHOD)**

@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();
}

我们看到注解需要传入一个key为value的数组ElementType[] value()。点开ElementType[]

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE, // 可用于类、接口或enum声明

    /** 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 // 类型的使用
}

ElementType枚举定义了各种注解使用的范围。

测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-akKYsn0s-1640144215217)(image-20211222094908620.png)]
缺失value
在这里插入图片描述
不传参数直接报错,应为注解内部定义了ElementType[] value()
在这里插入图片描述
将自定义注解的作用域设置到方法上,只能在方法上使用,在类上使用报错。
在这里插入图片描述
传入两个参数作用域,限制注解在方法和类上使用,我们发现注解可以在类上面正常使用了。

@Retention

@Retention注解声明了注解使用的周期,用于定义注解的存活阶段,可以存活在源码级别、编译级别(字节码级别)、运行时级别。

以**@Override注解为例,我们打开@Override**注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

进入**@Retention(RetentionPolicy.SOURCE)**

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

注解需要传入一个key为value的RetentionPolicy,进入RetentionPolicy

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,	// 源码级别,注解只存在源码中,一般用于和编译器交互,用于检测代码。如@Override, @SuppressWarings。注解将被编译器丢弃 

    /**
     * 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, // 字节码级别,注解存在于源码和字节码文件中,主要用于编译时生成额外的文件,如XML,Java文件等,
    		// 但运行时无法获得。 如mybatis生成实体和映射文件,这个级别需要添加JVM加载时候的代理(javaagent)
    		// 使用代理来动态修改字节码文件。
    		// 注解在class文件中可用,但会被VM丢弃

    /**
     * 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 // 运行时级别,注解存在于源码、字节码、java虚拟机中,主要用于运行时,可以使用反射获取相关的信息。
        	// VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
}

RetentionPolicy枚举定义了三个时间周期级别,大小是源码级别 < 字节码级别 < 运行时级别

@Documented

将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。

注解里面什么都没有,只是简单的标注

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

允许子类继承父类中的注解。也只是一个简单的标注。

以上四个元注解重点掌握@Target、@Retention

自定义注解

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

@interface 用来声明一个注解,格式是:修饰符 @interface 注解名{定义内容}

  • 内容中的每一个方法实际上是声明了一个配置参数,方法的名称就是参数的名称,方法的返回值类型就是参数的类型
  • 返回值类型只能是基本类型、Class、String、enum,如果返回值是String[]的时候,赋值的时候要用{“X1”, “X2”}这种形式;
  • 可以通过default来声明参数的默认值,声明默认值的可以不在自定义注解中赋值,反之必须赋值
  • 如果只有一个参数成员,一般参数名使用value字段,这是因为当参数名称是value并且自定义注解中只需要写一个参数的时候,可以省略参数名称,只有value可以这样,其他的都不行
  • 注解元素必须有值,我们定义注解元素时,经常使用空字符串、0、-1等作为默认值,当默认值为-1,代表不存在

我们来定义一个注解:

@MyAnnotation2(age = 18, name = "张三")
public class Demo02 {

}

/**
 * @author HCAN
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {

    // 注解的参数:参数类型 + 参数名称();这里的括号不是表示方法,而是定义了注解一个参数
    String name() default "";

    int age();

    int id() default -1;

    String[] schools() default {"清华大学", "北京大学"};

}

说明:

1、自定义注解内部定义的name()这个是表示的定义的注解参数,不是方法。

2、如果在注解的参数定义的时候设置了default默认值,在使用参数的时候可以不传,如果没有定义就必须传参数,否则会提示报错。

3、注解的参数传入顺序和定义参数的顺序无关。比如name()在age()前面,但是我们使用注解的时候是可以把age放在name前面的。

扩展:

我们发现前面我们在查看@Target注解内容的时候发现以下代码

@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();
}

我们明明将注解的参数名定义成了value(),为什么我们使用的使用的方式是@Target(ElementType.TYPE),没有使用@Target(value = ElementType.TYPE)

这是应为当我们注解参数只有一个的时候,我们可以把参数的名称定义为value(只能是value)。这样我们在使用注解的时候可以不写value,直接传入参数即可

鸣谢

本文为狂神说学习笔记
学习地址:https://www.bilibili.com/video/BV1p4411P7V3

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值