Java注解使用及原理解析
基本特性
1、jdk 1.5之后才引入的。
2、用来说明程序的。(注释是给程序员看的,注解就是给电脑看的)
java注解的作用分类
1、编写文档:通过代码标识的注解生成文档。【生成doc文档】
2、代码分析:通过代码标识的注解对代码进行分析。【使用反射】
3、编译检查:通过代码标识的注解让编译器能够实现基本的编译检查。【override】
测试类:
/** * 我的javadoc测试 */ public class testcode { /** * 计算两个数的和 * @param a 整数a * @param b 整数b * @return 返回两个数的和 */ public int add(int a, int b){ return a+b; } }
对于2、3两点我们应该是知道的。尽管可能不知道里面的原理。但是是平时都在用的。但是对于1点还可以生成doc文档?
测试操作如下:
d:\soft\jdk\bin\javadoc.exe .\testcode.java -encoding utf-8 -docencoding utf-8 -charset utf-8
生成了一大堆的东西:
打开testcode.html可以发现,我们的java api手册就是这样生产的。
注解来源分类
1、jdk自带的注解,如常见的override(重写校验),deprecated(表示弃用)
2、自定义的注解
1)格式, 以override为例:
2)注解的本质
我们编写一个简单的注解
myannotation.java
public @interface myannotation {}
我们通过编译和反编译看下最终是什么样的结果:
d:\soft\jdk\bin\javac.exe myannotation.java
d:\soft\jdk\bin\javap.exe myannotation.class
结果如下:
public interface myannotation extends java.lang.annotation.annotation {
}
可以发现注解的本质就是接口,这个接口继承了jdk里面的annotation接口。
3)注解的属性
由于注解本质为接口,那么里面可以定义未实现的方法。这些称为注解的“属性”。
属性的返回类型有(返回值不能为void):
- 基本数据类型
- string
- 枚举
- 注解
- 以及以上四种类型的数组
例子:
public enum person { ps; } public @interface annotation2 { } public @interface myannotation { string stringvalue(); int integervalue(); person personvalue(); annotation2 myannotationvalue(); string[] stringarrayvalue(); }
属性的使用,需要注意几点:
- 定义了属性在使用的时候就要给属性赋值,除非设置default值。如:string stringvalue() default "aaa";
- 如果属性为value且属性只有这一个,那么value可以省略,直接填写属性值。
- 如果是数组,需要用{}包含起来。
public @interface myannotation { string stringvalue() default "xxx"; int integervalue(); string[] stringarrayvalue(); } public @interface annotation2 { string value(); } @myannotation(integervalue = 1, stringarrayvalue = {"aaa", "bbb"}) @annotation2("default") public class testcode { /** * 计算两个数的和 * @param a 整数a * @param b 整数b * @return 返回两个数的和 */ public int add(int a, int b){ return a+b; } @override public string tostring() { return super.tostring(); } }
元注解
元注解是你在编写注解的时候,上面加的注解,就是注解的注解。主要有4个。
- @target, 用于指定注解的使用位置。如@target(elementtype.annotation_type),@target(value = {elementtype.type, elementtype.field, elementtype.method})。
- @inherited,表示父类加了这个注解,子类也自动加上。
- @documented, 表示这个注解的信息在执行javadoc的时候是否抽取到api文档中。
- @retention,表示注解被保留的阶段,java类,class文件,以及被jvm读取。总共三种。retentionpolicy.source, retentionpolicy.class, retentionpolicy.runtime
元注解的内容,可以到jdk源码里面看一下,更有利于理解。
解析注解
这个是最关键了,以上加了这么多的属性,并且还为这些属性附了值,那么是希望程序读取这些值,进行使用的。那其实就是要看如何拿到这些注解配置的值。
测试:
myannotition.java:
package annotation_; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; @target(elementtype.type) @retention(retentionpolicy.runtime) public @interface myannotation { string stringvalue() default "xxx"; int integervalue(); }
testcode.java:
package annotation_; @myannotation(integervalue = 1) public class testcode { public static void main(string[] args) { class<testcode> testcodeclass = testcode.class; myannotation myannotation = testcodeclass.getannotation(myannotation.class); int i = myannotation.integervalue(); string s = myannotation.stringvalue(); system.out.printf("i = %d, s = %s\n", i, s); } }
输出结果:
connected to the target vm, address: '127.0.0.1:49586', transport: 'socket'
i = 1, s = xxx
disconnected from the target vm, address: '127.0.0.1:49586', transport: 'socket'process finished with exit code 0
是不是感觉可以当配置文件使用。但是最主要的问题是myannotation.integervalue(),myannotation.stringvalue()为什么可以拿到对应的值,这个也是最核心的问题。
那就是getannotation里面返回了一个实现了myannotation注解(注解的本质是接口)的实例。这个类大概是长这样的。
package annotation_; import java.lang.annotation.annotation; public class myannotationimpl implements myannotation{ public string stringvalue() { return "xxx"; } public int integervalue() { return 0; } public class<? extends annotation> annotationtype() { return null; } }
所以就可以通过抽象方法获取到对应的值。(如何生成这样的一个类,只是学习注解,可以不关心。要不然,只能看里面的源码。因为如果自定义注解,你只会用到这一步,去获取值。)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。