整天都说注解注解注解,你们了解注解吗来自——面试官的灵魂拷问

注解

它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件、或者运行时中出现(SOURCE/CLASS/RUNTIME)。

元注解作用

如果要对于元数据的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

编写文档:通过代码里标识的元数据生成文档。

代码分析:通过代码里标识的元数据对代码进行分析。

编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查

1、注解的作用分类

(1)生成文档相关的注释说明:通过代码里标识的注解可以生成文档相关的注释说明。

下面我们就来演示一下,首先我们编写一个类,添加相关的注解。

/**

*@authorMr.wu

*@version1.0

*@since1.8

*/

publicclassAnnotationDemo{

/**

    *

*@parama

*@paramb

*@returna+b

    */

publicintsum(inta,intb){

returna+b;

}

}

然后使用javadoc指令把我们创建的类生成javadoc文档。

生成之后,如下图所示:

打开文档,如下图所示:

我们平时使用的JDK的文档就是这样生成的。

(2)分析运行代码:通过代码里标识的注解对代码进行分析运行[使用反射]。 最后会进行演示。

(3)编译检查:通过代码里的注解让编译器实现编译检查。 例如:我们平时经常使用的override注解,当我们使用此注解时,编译器就会检查该方法是否重写了父类(或接口)中的方法。

2、JDK内置注解

JDK中内置了三个基本的注解,下面就来介绍一下:

@Override: 限定重写父类中方法, 该注解只能用于方法;

@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时,通常是因为所修饰的结构危险或存在更好的选择;

@SuppressWarnings: 抑制编译器警告。

3、JDK中的元注解

元注解就是修饰注解的注解。JDK中有四个元注解

@Target:表示注解能够作用的位置。

(1) ElementType.TYPE :可以作用在类、接口和枚举类上; (2) ElementType.METHOD :可以作用在方法上; (3) ElementType.FIELD :可以作用在成员变量上; (4) ElementType.CONSTRUCTOR :可以作用在构造器上; (5) ElementType.LOCAL_VARIABLE :可以作用在局部变量上。

@Retention:表示注解的生命周期,即注解被保留的阶段。

(1) RetentionPolicy.SOURCE :在源文件中有效(即源文件保留),编译时编译器会直接丢弃这种策略的注解; (2) RetentionPolicy.CLASS : 在class文件中有效(即class保留),当运行Java程序时, JVM不会保留注解。这是默认值 (3) RetentionPolicy.RUNTIME : 在运行时有效(即运行时保留),当运行 Java 程序时, JVM会保留注解。程序可以通过反射获取该注释。

@Documented:表示该注解修饰的注解,可以被抽取到API文档中。 注意:定义为Documented的注解必须设置Retention值为RetentionPolicy.RUNTIME 。

@Inherited:表示该注解可以被人类继承。

4、自定义注解

自定义注解很简单,格式为:

元注解

public@interface注解

自定义注解时,还有一些要求:

Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以及以上所有类型的数组;

可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值时使用 default 关键字。指定初始化值的注解,在使用时可以不对成员变量进行赋值。

如果只有一个成员变量,建议使用参数名为value;

如果定义的注解含有成员变量,那么使用时必须进行赋值,除非它有默认值,赋值的格式为“成员变量名 = 值”;如果只有一个成员变量,且名称为value,则可以省略“value=”直接赋值;

没有定义成员变量的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数据。

下面我们就来自定义一个简单的注解

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public@interfaceMyAnnotation {

Stringvalue();

}

那么注解的实质是什么呢?

我们把我们自定义的注解反编译一下,如下图所示:

publicinterfacezzuli.edu.annotation.MyAnnotationextendsjava.lang.annotation.Annotation{

publicabstractjava.lang.Stringvalue();

}

由反编译后的代码可知,注解的本质实际上是一个接口,并且该接口默认继承了 Annotation 接口。

5、JDK8中注解的新特性

Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。

@Repeatable:可重复注解

当我们需要重复使用某个注解时,并且希望利用相同的注解来表现不同的形式时,我们可以借助@Repeatable注解。比如:我们在生活中一个人往往是具有多种身份,例如我是一家公司的员工,同时我还是我父母的孩子等等,此时我们就可以使用@Repeatable注解来完成。

在Java 8之前没有@Repeatable时,我们都是通过定义注解的数组来实现可重复注解的,如下所示:

//定义一个表示角色的注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Role {

String value();

}

//定义一个角色数组的注解,表示可重复的注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Roles {

Role[] value();

}

//使用表示可重复注解的Roles注解来表示人所扮演的不同的角色

@Roles({@Role("employee") ,@Role("son")})

publicclassPeople{

}

在Java 8中出现了@Repeatable可重复注解之后,变得简单了很多。下面我们就来演示一下,还是使用上面的例子,方便我们进行对比。

//定义一个Role注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Repeatable(Roles.class) //表示Role注解是一个可重复注解

public @interface Role {

String value();

}

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Roles {

Role[] value();

}

@Role("employee")

@Role("son")

public class People {

}

类型注解

JDK1.8之后,关于元注解@Target的参数类型ElementType枚举值多了两个:TYPE_PARAMETER、TYPE_USE。 (1) ElementType.TYPE_PARAMETER:表示该注解能写在类型变量的声明语句中,如:参数声明、泛型声明等; (2) ElementType.TYPE_USE:表示该注解能写在使用类型的任何语句中。

6、注解的底层实现原理

我们在使用框架时经常会使用注解,那注解底层到底是怎样执行的呢?下面我们通过一个例子来演示一下:

例子:自定义一个注解,注解标注在哪里就让哪个方法执行。

//自定义一个注解

@Retention(RetentionPolicy.RUNTIME)

public @interface MyJunit {

}

public class PrintNumber {

public void showOdd(){//打印奇数

for(inti =0; i <10; i++) {

if(i %2!=0) {

System.out.print(i+" ");

}

}

}

@MyJunit

public void showEven(){//打印偶数

for(inti =0; i <10; i++) {

if(i %2==0) {

System.out.print(i+" ");

}

}

}

}

public class JunitTest {

public static void main(String[] args) throws Exception {

//1.创建PrintNumber对象

PrintNumber printNumber = new PrintNumber();

//2.获取该类的字节码文件对象

Class clazz = printNumber.getClass();

//3.获取对象中的所有方法

Method[] methods = clazz.getMethods();

for(Method method:methods) {

//4.判断方法上是否有@MyJunit注解

boolean flag = method.isAnnotationPresent(MyJunit.class);

//5.如果方法上有@MyJunit注解,则执行

if(flag){

method.invoke(printNumber);

}

}

}

}

运行结果

由上述代码可知,注解底层是通过反射实现的。

易错点:由于注解默认的生命周期是在class文件中有效,当运行Java程序时, 注解就会失效。 所以我们在自定义注解时,要想在运行时使用,则应该把注解的生命周期设置为运行时有效(RetentionPolicy.RUNTIME),否则会报错。

总结

java提供的Documented元注解跟Javadoc的作用是差不多的,其实它存在的好处是开发人员可以定制Javadoc不支持的文档属性,并在开发中应用。如果对技术文章,以及干货内容,程序员生活类文章,感兴趣的朋友们可以关注收藏转发一下,期待下一次的文章吗,那就抓紧关注我吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271