java 元数据 和 元注解

简介: java 元数据 和 元注解。帮你看懂源码。
  • 基本介绍
  • 三种基本注解
  • @Override
  • @Deprecated
  • @SuppressWarnings
  • 四种元注解
  • @Retention
  • @Target
  • @Documented
  • @@Inherited

一、基本介绍

1.概述

java注解(Annotation)[ˌ  ænəˈ  teɪʃn],又称java标注,也被称为元数据(关于数据的数据,描述数据的数据)(Metadata)[ˈ  metədeɪtə],可用于修饰或者解释包、类、方法、属性、构造器,局部变量等数据信息

java注解和注释一样,不会影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。在javaSE中,注解的功能比较单一,例如标记过时的功能,忽略警告等等。但注解在javaEE中占据了更重要的角色,尤其是在使用框架时,例如用来配置应用程序的任何切面,代替javaEE旧版中所残留的冗余代码和XML配置等等。

2.使用

使用Annotation时,要在它前面增加“@”符号,并把该注解当作一个修饰符来使用。以修饰它支持的程序元素。


二、3种基本注解

0.总览 :

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记某个程序元素(类或者方法等)已过时。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

1.“@Override”:

①含义

Override就是重写的意思,如下 :

image.png

②源码

@Override最大的价值在于它的判断功能。通过Ctrl + b/B 可以查看@Override源码,如下 :

/** Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/packagejava.lang;
importjava.lang.annotation.*;
/*** Indicates that a method declaration is intended to override a* method declaration in a supertype. If a method is annotated with* this annotation type compilers are required to generate an error* message unless at least one of the following conditions hold:** <ul><li>* The method does override or implement a method declared in a* supertype.* </li><li>* The method has a signature that is override-equivalent to that of* any public method declared in {@linkplain Object}.* </li></ul>** @author  Peter von der Ah&eacute;* @author  Joshua Bloch* @jls 8.4.8 Inheritance, Overriding, and Hiding* @jls 9.4.1 Inheritance and Overriding* @jls 9.6.4.4 @Override* @since 1.5*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public@interfaceOverride {
}

其实,@Override源码中,最重要的无非最后两行。“@interface”表示Override是一个注解类,而不是接口。

“@Override”只能修饰方法,不能修饰其他程序元素(比如类,包,属性等)。这一点,其实源码中也有体现——Override源码中的“@Target(ElementType.METHOD)”明确指出了修饰的元素类型是METHOD(方法)。

PS : “@Target”用于修饰注解的注解,我们称之为“元注解”。

2.“@Deprecated”:

①含义

Deprecated就是不赞成的意思,如下 :

image.png

②源码

“@Deprecated”可以标记过时的程序元素。仍然通过Ctrl + b/B 快捷键追溯一下Deprecated的源码,如下 : (这次仅截取关键部分)

packagejava.lang;
importjava.lang.annotation.*;
importstaticjava.lang.annotation.ElementType.*;
@Documented@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public@interfaceDeprecated {
Stringsince() default"";
booleanforRemoval() defaultfalse;
}

同样,“@interface”表示Deprecated是一个注解类。而“@Target”元注解中,也标注出了@Deprecated可以修饰的数据元素,从左往右依次为 : {构造器,属性,局部变量,方法,包,模块,参数,类型(即类)}

③使用

“@Deprecated”修饰的程序元素并非无法使用,只是不建议使用。来举个栗子。

演示 :

packageadvanced.Annotation;
/*** @author : Cyan_RA9* @version : 5.0*/publicclassDeprecated_ {
@Deprecatedpublicvoidf() {
System.out.println("这方法没啥屁用,不建议使用。你非要用当我没说。。。");
    }
}
classTest {
publicstaticvoidmain(String[] args) {
Deprecated_deprecated_=newDeprecated_();
deprecated_.f();
    }
}

运行结果 :

image.png

其实,当你在调用@Deprecated注解修饰的方法时,IDEA就会给出提示,如下图所示 :

image.png

可以明显看到被“@Deprecated”注解修饰的f() 方法是被删除线“      ”标注的。

④补充

啥时候用“@Deprecated”比较多?

比如,当JDK进行版本更迭的时候,新版本的JDK对旧版本的某些类或者某些方法进行了更新,可能会定义新的类型,这时候就会在旧版本的对应类型或者对应方法前打上@Deprecated标注,提醒java人们这是旧的啦,建议你用新的捏。

3.“@SuppressWarnings” :

①含义

SuppressWarnings就是抑制警告,禁止警告的意思,如下 : (Warnings小学词汇)

image.png

②格式

“@SuppressWarnings”的使用与前面两个注解略有出入。使用格式如下 :

@SuppressWarnings("explanation1", "explanation2", "explanation3", ......)
//双引号中的说明信息不同,达到的抑制警告效果便不同。

③属性说明汇总

“@SuppressWarnings”中常见的属性说明有 :

"all"

抑制所有警告

"boxing"

抑制与“封装/拆装”相关的警告

"cast"

抑制与"强转类型"相关的警告

"dep-ann"

抑制与"淘汰注释"相关的警告

"deprecation"

抑制与"淘汰"相关的警告

"fallthrough"

抑制与"switch陈述式中遗漏break"相关的警告

"finally"

抑制与"未传回finally区块"相关的警告

"hiding"

抑制与"隐藏变数的区域变数"相关的警告

"incomplete-switch"

抑制与"switch陈述式(enum case)中遗漏项目"相关的警告

"javadoc"

抑制与"javadoc"相关的警告

"nls"

抑制与"非nls字串文字"相关的警告

"resource"

抑制与"使用Closeable类型的资源"相关的警告

"null"

抑制与"空值分析"相关的警告

"rawtypes"

抑制与"使用raw类型"相关的警告(泛型)

"restriction"

抑制与"使用不建议或禁止参照"相关的警告

"serial"

抑制与"可序列化的类别遗漏serialVersionUID栏位"相关的警告

"static-access"

抑制与"静态存取不正确"相关的警告

"static-method"

抑制与"可能宣告为static的方法"相关的警告

"super"

抑制与"置换方法相关但不含super呼叫"的警告

"synthetic-access"

抑制与"内部类别的存取未最佳化"相关的警告

"sync-override"

抑制"因置换同步方法而遗漏同步化"的警告

"unchecked"

抑制与"未检查的作业"相关的警告

"unqualified-field-access"

抑制与"栏位存取不合格"相关的警告

"unused"

抑制与"未用的程式码和停用的程式码"相关的警告(变量未使用)

部分属性演示 :

packageadvanced.Annotation;
importjava.util.ArrayList;
importjava.util.List;
/*** @author : Cyan_RA9* @version : 5.0*/@SuppressWarnings({})
publicclassSuppressWarnings_ {
publicstaticvoidmain(String[] args) {
Listlist=newArrayList();
list.add("");
list.add(1);
list.add(1);
inti;
System.out.println(list.get(2));
    }
}

警告信息如下图所示 :

image.png

这时候可以通过在注解“@SuppressWarnings”中分别添加"rawtypes", "unchecked", "unused"属性说明来去除警告信息。如下图所示 :

image.png

添加属性说明后,全部消失了,如下图所示 :

image.png

⑤作用域

关于@SuppressWarnings注解的作用域 : 取决于该注解的定义位置

eg : 当它放在main方法前时,抑制警告的范围就是main函数;当它定义在类上,作用域就是整个类;当然,也可以在固定的警告语句上面使用@SuppressWarnings注解,通过传入指定的属性说明实现精准的消除警告。

⑥源码

通过Ctrl + b/B快捷键快速追溯到SuppressWarnings注解类的源码,源码如下 : (仅截取关键部分)

packagejava.lang;
importjava.lang.annotation.*;
importstaticjava.lang.annotation.ElementType.*;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public@interfaceSuppressWarnings {
String[] value();
}

同样的。"@interface"元注解表明SuppressWarnings是一个注解类。而“@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})”表明了@SuppressWarnings注解的使用范围,从左往后依次是”{类型(类),属性,方法,参数,构造器,局部变量,模块}“

三、4种元注解

0.总览 :

在Java中,将“修饰注解的注解”称为元注解。元注解使用并不多,本身作用也没多大,了解即可。可以看懂源码就足够了。

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问(保存时间)。
  • @Documented - 标记这些注解是否包含在javadoc用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员(可以作用于哪些程序元素)。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

1.“@Retention”:

①含义

Retention就是保持,保留的意思,如下图所示 :

image.png

②使用

“@Retention”只能用于修饰一个注解定义,用于指定该注解可以保留多长时间,@Retention元注解中包含一个RetentionPolicy类型的成员变量,使用@Retention元注解时,必须为该成员变量指定值。

RetentionPolicy成员变量三种值 :

RetentionPolicy.SOURCE

编译器使用后,直接丢弃这种策略的注解

RetentionPolicy.CLASS

编译器将把注解记录在class文件中,当运行程序时,jvm不会保留注解,这是成员变量的默认值

RetentionPolicy.RUNTIME

编译器将把注解记录在class文件中,当运行程序时,jvm会保留注解,程序可以通过反射获取该注解。

③示意图

三种成员变量值的效果如下 :

image.png

演示 :

以Override的源码为例,如下:(仅截取关键部分)

packagejava.lang;
importjava.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public@interfaceOverride {
}

注意看,“@Retention(RetentionPolicy.SOURCE)”中,RetentionPolicy类枚举常量是SOURCE,这就表示“@Override”注解生效的范围仅仅在.java的源文件中,不会在.class文件中生效,也不会在程序运行时被jvm读取。

2."@Target" :

①含义

Target就是目标的意思,如下图所示 :

image.png

②使用

@Target元注解可以指明当前注解可以作用于哪些程序元素。之前的三大基本注解中,均演示过”@Target“元注解。如下 :


image.png


③源码

Target元注解源码如下:(仅截取了重要部分)

packagejava.lang.annotation;
@Documented@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public@interfaceTarget {
ElementType[] value();
}

可以看到Target底层是一个ElementType类型的数组。而通过Ctrl + b/B追溯源码,我们可以看到ElementType本质上是一个枚举类。如下 :

packagejava.lang.annotation;
publicenumElementType {
/** Class, interface (including annotation interface), enum, or record* declaration */TYPE,
/** Field declaration (includes enum constants) */FIELD,
/** Method declaration */METHOD,
/** Formal parameter declaration */PARAMETER,
/** Constructor declaration */CONSTRUCTOR,
/** Local variable declaration */LOCAL_VARIABLE,
/** Annotation interface declaration (Formerly known as an annotation type.) */ANNOTATION_TYPE,
/** Package declaration */PACKAGE,
/*** Type parameter declaration** @since 1.8*/TYPE_PARAMETER,
/*** Use of a type** @since 1.8*/TYPE_USE,
/*** Module declaration.** @since 9*/MODULE,
/*** Record component** @jls 8.10.3 Record Members* @jls 9.7.4 Where Annotations May Appear** @since 16*/RECORD_COMPONENT;
}

ElementType枚举类中的这些枚举常量,其实就是我们说的”程序元素“。即注解可作用于的程序成分。

3.”@Documented“ :

①含义

Documented就是登记在案,文件化的意思,如下图所示 :

image.png

②使用

“@Documented”元注解修饰的注解类,会在javadoc文件中显式地呈现

演示 :

先定义一个注解类Demo,并在该注解类中使用@Documented元注解修饰。如下 :

packageadvanced.Annotation;
importjava.lang.annotation.*;
/*** @author : Cyan_RA9* @version : 2.0*/@Documented@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public@interfaceDemo {
//自定义一个注解类。}

然后在定义一个测试类Test_EX,并在测试类中定义两个方法,用自定义的注解”@Demo“去修饰方法。如下 :

packageadvanced.Annotation.test;
importadvanced.Annotation.Demo;
/*** @author : Cyan_RA9* @version : 1.0*/classTest_EX {
@Demopublicvoidgreet() {
System.out.println("Hello!");
    }
@Demopublicvoideat() {
System.out.println("美汁儿美汁儿~");
    }
}

然后通过IDEA自带的生成javadoc的功能生成该测试类的javadoc文件,如下GIF图所示 :

image.png

可以看到,greet方法和eat方法的”@Demo“都保留在了生成的javadoc文件中。

4.”@Inherited“ :

①含义

Inherited就是继承的意思,如下所示 :

image.png

②使用

如果每个类使用了注解,而这种注解恰好被”@Inherited“元注解修饰,那么该类的子类同样会自动拥有父类的注解。


System.out.println("END-----------------------------------------------");

目录
相关文章
|
11月前
|
Java 编译器
【Java基础】 - 常用注解@SuppressWarings
【Java基础】 - 常用注解@SuppressWarings
107 1
|
3月前
|
Java
[Java]自定义注解
[Java]自定义注解
57 0
|
10月前
|
Java 编译器 API
java之注解的定义和使用
java之注解的定义和使用
|
Java
Java -- 元注解
@Target(ElementType.ANNOTATION_TYPE):指定该注解可以用于注解类、接口或枚举类型。 @Retention(RetentionPolicy.RUNTIME):指定该注解的保留策略,即在程序运行时也可以访问到该注解。 @Documented:指定该注解应该被包含在 Java 文档中。 @Inherited:指定该注解可以继承自父类。
47 0
|
Java Spring
【Java 】 如何通过 反射 获取 注解信息 ?
在框架中如何通过 反射 获取到 类或方法 上的 注解信息
147 0
|
Java 容器
Java-元注解
Java-元注解
|
Java 编译器 Spring
java元注解
java注解只是一种不会被编译器忽略的注释。本身对代码逻辑没有任何影响(可以用来判断是否存在,能读取内容信息),其使用效果完全由使用工具决定。
56 0
|
XML Java 编译器
Java基础篇 - 注解
Java基础篇 - 注解
|
XML 架构师 安全
java中《自定义注解》的使用
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释 补充导读:相信很多同学看完之后是整不明白的,为什么呢是因为我们用专业名词去解释了专业名词,所以你才会不懂的,那么我们该怎么办呢
526 0