博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 基础知识 注解 annotation
阅读量:2208 次
发布时间:2019-05-04

本文共 7189 字,大约阅读时间需要 23 分钟。

一:什么是注解

注解,如果看他的定义,可能会很迷糊

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

元数据,为程序提供数据,不是程序的一部分,对代码没有直接的影响

让人看得很懵

我个人觉得注解可以理解为 “标签” 或者是 “便利贴”


二:注解的类型

(1)对代码的注解

首先,注解会带有信息,或是告诉编译器

@Override	public String elementName() {
return null; }

上面这个应该是最常见到的注解了

Override 覆盖,也就是写一些新的东西把原来的内容覆盖掉

通常应用于接口的实现

其作用是:

告诉编译器,下面这个方法是需要被 “覆盖” 的

如果这个注解下的方法,你没有重新写一些新内容进行覆盖

编译器会提示你:(你用像Eclipse 这样的IDE时,马上就会有高亮报错了)

The method xx() of type X must override or implement a supertype method

就是提醒你得去override 的意思

建 议 直 接 去 I D E 里 试 试 , 这 真 难 以 用 文 字 表 达 \color{blue}{建议直接去IDE里试试,这真难以用文字表达} IDE

①注解就和标签一样,你贴上去,作提醒用

@Override是Java内置的作用于Java代码的注解,与之同类型的注解还有:

@Deprecated 和 @SuppressWarnings

它们的作用

@Deprecated:声明一个方法是过时被淘汰的,一旦被调用会有Warning警告

(在Eclipse中,被声明的方法会被划线,像这样sayHello()

例:

@Deprecatedvoid sayHello(){
System.out.print("hello");}

@SuppressWarnings:可以抑制Warning警告

(警告不是报错,程序仍可运行,只是编译器会对一些不好的情况做出高亮提醒,抑制即消除高亮)

例:

@SuppressWarnings("unused")	int a=1;

声明了变量不使用的话,编译器是会发出警告的

而我们可以使用@SuppressWarnings(“unused”) 抑制这个警告

(Ps:@SuppressWarnings 需要像 “unused” 这样的参数来告诉编译器

这里需要抑制什么类型的警告

对于@SuppressWarnings,像这样的参数还有很多,我就不展开了,大家可以去查阅相关资料)


(2)对注解的注解

(这里只介绍@Target和@Detention 还有很多其他的注解大家就自行学习了)

上面介绍的三个内置注解,是对代码的注解

除此之外,还有对注解的注解

别懵逼,这就解释~

注 解 的 位 置 − − @ T a r g e t \color{red}{注解的位置--@Target} @Target

已经给了几个例子,大家可能会发现,注解可以放在很多不同的位置

有对方法的注解,有对变量的注解

其实呢,也可以对类进行注解,还可以放在参数的位置,像这样

String s="say";say(@InsertNew("good") s);

默认情况下,编译器不会限制你放注解的位置

但有时,我们就是要限制这个注解的位置,不让它到处乱放

就需要用到@Target注解了

例:

@Target(ElementType.PARAMETER)@InsertNew

则表示这个注解只能放在参数(parameter)的位置

不然会报错

The annotation @InsertNew is disallowed for this location

Ps:对注解的注解@Target并不是内置注解,需要import

import java.lang.annotation.Target;

import java.lang.annotation.ElementType;

常用的参数有:

TYPE----------------对类注解

METHOD-----------对方法注解
PARAMETER-----对参数注解
FIELD---------------对成员变量注解

还有等等我就懒得列出来了~


注 解 的 生 命 周 期 − − @ D e t e n t i o n \color{red}{注解的生命周期--@Detention} @Detention

上面介绍过,我把注解比作是 “便利贴”

原因是它并不是一直依附于代码的,它可以被 “撕下来”

注解有这样一种机制:

把Java代码编译成.class文件时,注解可能会被消除掉

把.class 进JVM时,注解也可能会被设为不可见

这也是定义中说的 “注解不是代码的一部分” 的原因

而决定注解什么时候会被消除的正是对注解的注解

@Retention

例:

@Retention(RetentionPolicy.RUNTIME)public @interface InsertNew {
}

上面的是自定义的注解—InsertNew

@Retention (保留)的作用正是用来声明这个注解的生命周期的

它也像@SuppressWarnings一样需要参数具体说明

不过他的参数种类就少多了

RetentionPolicy.SOURCE(把Java代码编译成.class文件时,注解消除)

RetentionPolicy.CLASS(.class文件进入runtime时,注解不可见)
RetentionPolicy.RUNTIME(注解在.class文件进入runtime时可见)

(关于什么是可见,什么是不可见,下面再具体说明)

补充:@Retention 也需要 import

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

这个注解的具体使用还得等介绍了自定义注解(custom annotations)才说得清

马上介绍~


(3)自定义注解

注解带有的信息除了能够和编译器交流外,也可以供程序使用

注解在Java 中其实是一个特殊的接口

例:

当你使用一个自定义注解时

@InsertNew

会报错(因为还没有进行定义)

InsertNew cannot be resolved to a type

IDE还提醒你去创建一个annotation

create annotation InsertNew

然后,你可以直接点也可以自己手动创建

右键–New–annotation

创建好后是这样的

public @interface InsertNew{
}

下 面 介 绍 其 内 部 成 员 \color{red}{下面介绍其内部成员}

更确切地说,注解其实是个特殊的接口

public @interface InsertNew {
int b=10; int[] a=null; int[] a() default {
1,2,3,4}; String value() default "y"; String sayHello() default "hello world";}

注解可以有其成员变量和方法

在编译器的报错信息里他们被称为 “attribute” 属性

注意!

注解中的成员变量的类型是 public static final

注解中的成员方法的类型是public abstract

则有:

注解里的变量是静态变量,可以以类名.变量名 的形式访问

注解里的成员方法是抽象方法,没有函数体

实际的例子:

System.out.println(InsertNew.b);

输出:10

而这里的 “方法”,则是相当于一个setAttribute()

要想修改注解里attribute 的值,则同名同类型的 “方法” 不可少------例如上面的int[] a


注 解 缺 省 值 \color{red}{注解缺省值}

还记得之前例子中的@SuppressWarnings(“unused”) 吗

这其实是缺省的表达

完整的表达是这样的:

@SuppressWarnings(value=“unused”)

当 “value=” 缺省时,参数默认是给value的

而这里的value 对应的就是@SuppressWarnings里的value() 方法

(上面还说过@SuppressWarnings 需要参数不然会报错

原因也就是它里面的value() 方法没有设置default 默认值

对了,这个报错只针对特殊的value(),其他的成员方法可以不设置默认值

Ps:

方法的返回值也有限制(其实是对attribute 类型的限制)

only primitive type(像int,double), String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof


继 续 解 析 @ R e t e n t i o n \color{red}{继续解析@Retention} @Retention

上面介绍完自定义注解的定义

可以继续上面@Retention 的说明了

上面简单提及过他的三个参数

但是,在实际应用中,又有什么分别呢

来看例子:

@Retention(RetentionPolicy.RUNTIME)public @interface InsertNew {
int b=10; int[] a=null; int[] a() default {
1,2,3,4}; String value() default "y"; String sayHello() default "hello world";}

RUNTIME,也就是运行时

在这个 Retention(保留) 下,程序可以通过Java的反射机制获取注解中的 attribute

例: 如 何 利 用 反 射 获 取 注 解 的 值 \color{red}{如何利用反射获取注解的值}

public static void main(String[] args) {
//down here is the simplest one //deal with the annotation that declared in the head of a class--target is ElementType.TYPE InsertNew column = (InsertNew)Myclass.class.getAnnotation(InsertNew.class); if (column != null) System.out.println(column);//you can get the methods with default value in annotation //if you do not set the method for the attribute you can't see it directly in column else if you use the field way System.out.println(column.b);//you can get attribute with this---field way }

输出结果:

@com.annotation.InsertNew(value=y, a=[1, 2, 3, 4], sayHello=yes, b=11)

10

(com.annotation 是一个package,InsertNew 是自定义注解的类, Myclass是我自定义的一个类)

如果Detention 是CLASS 或SOURCE 的话,则无法看到这一行

@com.annotation.InsertNew(value=y, a=[1, 2, 3, 4], sayHello=yes, b=11)

(因为getAnnotation()方法会返回null))

但是,可以看到10,因为注解中的成员变量的类型是public static final

CLASS 和SOURCE 下,getAnnotation() 方法返回null的原因是不同的

CLASS下获取不到,是因为被设置了 “Invisible” 的属性

(所以尽管.class 文件中存在的注解但是在runtime 仍不可见的原因)

SOURCE下获取不到,是因为根本就没有

下面具体测试看看

使 用 j a v a p 反 编 译 . c l a s s 文 件 \color{red}{使用javap 反编译.class文件} 使javap.class

首先是.java文件

Myclass.java

@InsertNew(sayHello="yes",b=11) //annotation for TYPEpublic class Myclass{
int c=11; public int a=14; //if you do not set you will get the default one //sayHello you set here need a func in annotation //what's more, the implements is not the annotation, you can't use getAnnotation() public void say(String a) {
System.out.print("hello"); } }

InsertNew.java

@Retention(RetentionPolicy.RUNTIME)public @interface InsertNew {
int b=10; int[] a=null; int[] a() default {
1,2,3,4}; String value() default "y"; String sayHello() default "hello world";}

通过javac 得到.class文件

javac InsertNew.java Myclass.java

I n s e r t N e w 是 注 解 的 j a v a 文 件 , M y c l a s s 是 我 要 添 加 注 解 的 类 \color{blue}{InsertNew是注解的java文件,Myclass是我要添加注解的类} InsertNewjavaMyclass

使用javap -v 进行反编译,查看关于注解的情况

javap -v Myclass.class

(我们要研究是的被添加注解的类,所以反编译Myclass.class 就够了)

整个输出的内容有点长,我只展示我们需要的部分

原文:

SourceFile: “Myclass.java”

RuntimeVisibleAnnotations:
0: #20(#21=s#22,#23=I#24)

译:

SourceFile: “Myclass.java”

RuntimeVisibleAnnotations:
0: Lcom/dgut/annotation/InsertNew(sayHello=yes,b=11)

上面的是注解的@Retention为RUNRIME时的情况

下面是@Retention为CLASS的情况:

SourceFile: “Myclass.java”

RuntimeInvisibleAnnotations:
0: Lcom/dgut/annotation/InsertNew(sayHello=yes,b=11)

和RUNTIME 的不同只有一处就在

一个是

RuntimeVisibleAnnotations:

一个是

RuntimeInvisibleAnnotations:

下面再看看@Retention为SOURCE的情况:

SourceFile: “Myclass.java”

没了,连RuntimeInvisibleAnnotations:都没有

原因就是注解在被编译成.class文件时就被消除了


总结:

回到定义

注解是元数据,只提供信息,并不带逻辑操作,注解里的方法的是也只是抽象方法,并没有函数体


最后补充一点:注解有多个参数时

@SuppressWarnings({“unchecked”,”unused”})

转载地址:http://aoiyb.baihongyu.com/

你可能感兴趣的文章
【LEETCODE】106-Construct Binary Tree from Inorder and Postorder Traversal
查看>>
【LEETCODE】202-Happy Number
查看>>
和机器学习和计算机视觉相关的数学
查看>>
十个值得一试的开源深度学习框架
查看>>
【LEETCODE】240-Search a 2D Matrix II
查看>>
【LEETCODE】53-Maximum Subarray
查看>>
【LEETCODE】215-Kth Largest Element in an Array
查看>>
【LEETCODE】241-Different Ways to Add Parentheses
查看>>
【LEETCODE】312-Burst Balloons
查看>>
【LEETCODE】232-Implement Queue using Stacks
查看>>
【LEETCODE】225-Implement Stack using Queues
查看>>
【LEETCODE】155-Min Stack
查看>>
【LEETCODE】20-Valid Parentheses
查看>>
【LEETCODE】290-Word Pattern
查看>>
【LEETCODE】36-Valid Sudoku
查看>>
【LEETCODE】205-Isomorphic Strings
查看>>
【LEETCODE】204-Count Primes
查看>>
【LEETCODE】228-Summary Ranges
查看>>
【LEETCODE】27-Remove Element
查看>>
【LEETCODE】66-Plus One
查看>>