茨威格在《人类群星闪耀时》写到那些改变历史进程的小人物。原本默默无闻,却一鸣惊人。我们日常生活中,容易被忽略的细节,当真正了解它时,顿时"斯巴达"了。'Java注解类'在我心里就属于貌不惊人狠角色。
本文介绍注解类简介和如何自定义自己的注解类。
概要
单纯说注解,注解本身意义并不大。作为标签对对象的注释,比如生成doc的注释,函数已废弃.... 简单说和注释没啥区别。而它发挥巨大作用的是:注解解释类,也就是相关对代码进行解释的特定类。
注解类神奇功效是:通过注解和反射这两者的结合使用达成的。现在很多流行的开源框架都是基于注解类实现。可关注下spring rpc.....等各种开源框架。
本文内容包括:
- 注解类的介绍
- 自己动手写注解类
认识注解类
简单来说,注解类就是标签。只是标签分为不同的种类,对应的作用域和使用方式也千差万别。从功能上而言:这些标签分为: 基本注解、元注解、自定义注解。
基本注解
基本注解类是基于JVM虚拟机的语言,提供的系统注解。也是基本的通用注解类。
比如自Java 1.5版本以来提供的@override
、@deprecated
,和 1.8版本的@FunctionalInterface
...
元注解
在我们翻看注解类源码的时候,总会有如下定义:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
@Documented
,@Retention(RetentionPolicy.RUNTIME)
,@Target(ElementType.TYPE)
使用过注解,我们知道这些都是注解。为基本注解作注,意味者特殊身份 -- 元注解。
所以元注解定义是: 元注解
是标记其他注解注解。就有像标识性别是人必须的一个标签。元注解就像性别。描述人必须有性别,那么注解类也需要元注解标注。
元注解不能作用于具体函数变量等,如下操作报错@Target not applicatable to type
@Target() //func是使用方式,不是注解。所以不能作用
public void func() {
System.out.printf("test func");
}
只能作用于注解类上。那么,元注解又有哪些类别,功能又有哪些哪?
元注解分类
- Documented 文档注解表明它被 javadoc或相似工具记录,生成各种文档。
- @Target 用来约束注解用于范围(如方法、类或字段)。详细的作用范围有哪些,见
enum ElementType
- @Inherited:某个被标注的类型是被继承的。即注解类型自动从父类继承,是
父类
,但不会从接口继承。 - @Retention用来约束注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime)。
- SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
- CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等
- RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
- @Repeatable 描述标记的注解可重复注解的。
有限的元注解涵盖了文档、代码编译、运行时标注等功能。实际上,它量不大,功能却是大千世界。
自定义注解类
程序猿毛病之一:喜欢自己DIY
,什么都要自己练练。我也要手动写注解类。
下面代码包括:变量的自定义注解、和方法的自定义注解,以及通过代码如何读取到注解内容。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
String value() default "call test annotation";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodAnnotation {
String value() default "MethodAnnotation";
}
代码:把自定义注解分别用在函数和变量上
public class TestSelfAnnotation {
@MethodAnnotation(value="TestSelfAnnotation MethodAnnotation")
public void printAnnotation() {
System.out.printf("function printAnnotation");
}
@FieldAnnotation(value="TestSelfAnnotation field")
Integer testVar = 0;
/* void main(String [] args) {
TestSelfAnnotation a = new TestSelfAnnotation();
FieldAnnotation b = a.getClass().getAnnotation(FieldAnnotation.class);
System.out.printf(b.value());
}*/
}
测试用例,获取注解类
val a = new TestSelfAnnotation //定义类
a.printAnnotation() //调用函数
val b = a.getClass //获取类class
val anno = b.getDeclaredMethods
if(anno == null) println("anno is null") else println(s"anno not null ${anno.getClass.getName}")
for(mt <- anno) { //!!!!! 同一个方法中可以有多个注解类,所以需要指定注解,才能获取值
println(mt.getAnnotation(classOf[MethodAnnotation]).value())
}
val filed = b.getDeclaredField("testVar") //设定获取 testVar变量的注解
println(filed.getAnnotation(classOf[FieldAnnotation]).value()) // classOf需要指定注解类类型是 FieldAnnotation,而不是声明TestSelfAnnotation
function printAnnotation
anno not null ....
TestSelfAnnotation MethodAnnotation //不同注解作用对象不同
TestSelfAnnotation field
后续
文章是对java注解的入门介绍,接着自定义注解的例子。建立了解注解类的信心,为后续的使用注解对单体架构进行微服务化改造开个好头。
网友评论