Java注解
内容参考:
【注解】Annotation Target ElementType
https://www.cnblogs.com/baiqiantao/p/7469746.html
在这篇博客里已经将注解解释的相当详细, 在此基础上进行一定的增删.
加之在 Java编程思想这本书中, 有一章节专门用来介绍注解, 感兴趣的话可以看一下.
基础
在java中,注解作为程序的元数据嵌入到程序当中, 元数据标签的存在并不影响程序代码的编译和执行。
注解可以被一些解析工具或者是编译工具进行解析, 其信息可以在编译、加载和运行时被读取(具体详见元注解 Retention),并执行相应的处理。
什么是元数据
元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能.
其余地方就不再引用, 如注解的优缺点, 和XML文件的对比. 从这里已经有了基本的核心. 用来描述数据的数据.
在研究Java注解的具体功用, 特性等, 不如从案例开始;
public @interface TestAnnotation {
}
通过这种方式我们就定义了一个注解, @interface. 我们来看一个熟悉的注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
String value() default "";
}
这是Spring中的 @Controller注解, 那我们怎样解读这个注解呢?
@Controller("test")
//@Controller(value = "test")
public class TestController() {
}
使用方法解读
在编程思想中有一句很有趣的话, 如果没有处理解读注解的工具, 注解也不会比注释来的更有用处.
在真正解读之前,在这里提出几点关于注解的说明, 注解本身是类似于Java接口的, 但是有几点区别 :
- 注解的成员变量以无形参的方法形式来声明, 在这里表示的意思就是, 它是个成员变量, 长得像方法, 因此不要想着各种各样的实现, 其方法名和返回值定义了该成员变量的名字和类型。
- 成员变量的类型限定为:基本类型、String、Enums、Annotation(但不能是自身)或者是这些类型的数组, 甚至于返回值也可以是注解.
- 使用注解时, 需要为所有的成员变量都进行赋值, 除非使用default关键字设置默认值
- 当 成员变量 value 为唯一的需要被赋值的属性值(也就是只有value设置default时), 此时在使用时无需使用键值对的形式.(示例见下文)
- 注解可以被用来注解其他注解. 甚至可以注解自身.
对注解有了这些基本的了解, 继续来看, 如何解读一个注解?在我目前的理解中, 反射.
//定义注解, 在这里需要指定为RUNTIME, 否则无法通过反射获取到.
//因为反射特点之一就是 运行时执行.
@Retention(RetentionPolicy.RUNTIME)
public @interface TopClass {
String name();
String username() default "zzzxxxx";
}
@TopClass(name = "zzzzzz")
public class AnnotationTest {
}
public class ReadAnnotation {
public static void main(String[] args) {
TopClass tp = AnnotationTest.class.getAnnotation(TopClass.class);
System.out.println(tp.name());
System.out.println(tp.username());
}
}
结果输出 zzzzzz; zzzxxxx;
同时在 Class类中, 还有几种有关注解的处理方式, 就不多介绍了.而 Method, Field等其他类中都实现了对应的方法.
因此在Spring中指定了扫描的包, 会扫描对应的Class, 找到相应的注解, 创建相应的实例, 这种流程也就不难理解了.
元注解
Java为我们提供了4种元注解(元注解专门用来注解其他注解):
@Target, @Retention, @Documented, @Inherited-
如:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
元注解
-
@Target
这个注解被用来指定 注解可以用在什么地方.
其值 ElementType 表示类型:
public enum ElementType { TYPE, // 类, 接口(包括注解类型)或enum声明 FIELD, // 域声明, 包括enum实例 LOCAL_VARIABLE, // 局部变量 METHOD, // 方法声明 PACKAGE, // 包声明 PARAMETER, // 参数声明 CONSTRUCTOR, // 构造器声明 ANNOTATION_TYPE,// 作用目标是注解 TYPE_PARAMETER, // 看了好久都不明白, 这两个1.8注解的具体作用 TYPE_USE // }
而元注解本身都有 @Target(ElementType.ANNOTATION_TYPE) 所注解.
而如果不声明, 则可以用于任何地方.但在 Java8以后,如果不声明的话, TYPE_PARAMETER, TYPE_USE 所适合的场景并不能使用 相应注解.
-
Retention 保留策略
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); } public enum RetentionPolicy { SOURCE, //表明注解会被编译器忽略 CLASS, //表明注解仅在编译时使用, 在运行时被抛弃. RUNTIME //编译及运行时都会保留相应注解, 反射可用. }
默认值为: CLASS; 反射时必须指定为 RUNTIME;
-
Documented 文档化
-
Inherited 自动继承
指明如果父类使用了 被元注解 注解 的 注解, 此注解会被继承. 如果使用注解类型注解类以外的任何事物,此元注解类型都是无效的。还要注意,此元注解仅促成从超类继承注解;对已实现接口的注解无效。
目前来说就这么多, 依然遗留问题是, 1.8 ElementType中新添加的两个对象.