前言
在学习spring框架的时候在Ioc那部分有使用注解去配置的内容,我意外这是我第一次接触注解没想到细细学习后才发现,注解存在于Java的每一部分。
一、注解是什么?
概念:注解就是一种标记符号,可以在代码上的关键节点(类、方法、变量、参数、包)打上标记,然后程序在编译时或者运行时就可以检测到这些标记从而执行一些自己需要的功能操作。
二、使用方式
1.定义注解
用@Interface创建,并加上常用的注解,元注解或自定义注解类型元素。
public @interface ThisAnnotation {
String name();
}
2.基本作用
1.生成文档。这是最常见的,也是java 最早提供的注解;
2.在编译时进行格式检查。如@Override放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出;
3.跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量;
三、注解类型
1.基本注解
在java.lang包中提供了五个基本的Annotation,前3个比较常见,最后2个了解即可:
@Override:表示当前方法覆盖了父类的方法此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。
//父类
public class OverrideAnnotationFather {
public void study(){
System.out.println("father override...");
}
}
//子类
public class OverrideAnnotation extends OverrideAnnotationFather{
@Override
public void study() {
super.study();
}
}
@Deprecated:过时注解,用于标记已过时 & 被抛弃的元素(类、方法等)
public class DeprecatedAnnotation {
public static void main(String[] args) {
printAuthorInfo();
printAuthorInfo("aaa");
}
@Deprecated
public static void printAuthorInfo() {
System.out.println("this is Deprecated text");
}
public static void printAuthorInfo(String string) {
System.out.println(string);
}
}
@SuppressWarnings:抑制内容警告
public static void main(String[] args) {
@SuppressWarnings("rawtypes","unused")
Collection<String> collection = new ArrayList<>();
}
@SafeVarargs:参数安全类型注解,用于提醒开发者不要用参数做不安全的操作
@FunctionalInterface:函数式接口注解,用于指定接口是函数式接口。
2.元注解
ava还提供了元注解meta-annotation用于标记注解即注解注解的注解!;常见的元注解有:
@Target是一个指定可以使用的范围(类、方法、变量、参数、包)
@Target({ElementType.FIELD,ElementType.METHOD}) //多个的时候使用{}括起来,然后用逗号分隔开
public @interface TargetAnnotation {
}
// @Target(ElementType.TYPE) 作用接口、类、枚举、注解
// @Target(ElementType.FIELD) 作用属性字段、枚举的常量
// @Target(ElementType.METHOD) 作用方法
// @Target(ElementType.PARAMETER) 作用方法参数
// @Target(ElementType.CONSTRUCTOR) 作用构造函数
// @Target(ElementType.LOCAL_VARIABLE)作用局部变量
// @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
// @Target(ElementType.PACKAGE) 作用于包
// @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
// @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
// 一般比较常用的是ElementType.TYPE类型.
@Retention是指用来修饰自定义注解的生命周期。注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段(可以通过反射去操作目标注解)。
- RetentionPolicy.SOURCE 表示注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 RetentionPolicy.SOURCE是我们平常见得最多的保留策略。比如:@Override, @SuppressWarnings都采用了该策略。
- RetentionPolicy.CLASS 表示注解会被保留至编译进行时,但它并不会被加载到 JVM 中。 RetentionPolicy.CLASS是默认的注解保留策略。
- RetentionPolicy.RUNTIME 表示注解可保留至程序运行阶段,它会被加载进JVM 中。故,在程序运行时可读取该注解。RetentionPolicy.RUNTIME是一个非常有用的保留策略,尤其是在框架开发的时候。
@Inherited的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,则它的子类也继承了父类的注解(子类可以同时被其他注解修饰)。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InheritedAnnotation {
}
@MyAnnotation
public class ThisFatherClass {
}
public class ThisSonClass extends ThisFatherClass {
}
public class test {
public static void main(String[] args){
Class<SonClass> thissonClass = ThisSonClass.class;
InheritedAnnotation annotation =thissonClass.getAnnotation(InheritedAnnotation.class);
}
}
上面的例子,父类加了可继承注解,子类没有被该注解修饰,但是子类获取InheritedAnnotation注解成功,说明子类继承了父类中的InheritedAnnotation。
@Documented表示在生成javadoc文档时将该Annotation也写入到帮助文档。
@Target(ElementType.METHOD)
@Documented //此处,使用@Target(ElementType.METHOD)表示这个注解是用来修饰方法的,
//并且为该注解添加了元注解@Documented
public @interface DocumentedAnnotation {
String name();
}
public class CommonClass {
/**
* This is a java method
*/
@TestDocumented(name = "aaa")
public void testMethod() {
}
}
//最后,通过文档工具可生成类似如下所示的帮助文档:
//@TestDocumented(name = “google”)
//public void testMethod()
//This is a java method
3.自定义注解
使用规则:
(1).使用@interface关键字定义注解,注意关键字的位置
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。
(2).成员以无参数无异常的方式声明,注意区别一般类成员变量的声明
其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称
(3).可以使用default为成员指定一个默认值,如上所示
(4).成员类型是受限的,合法的类型包括原始类型以及String、Class、Annotation、Enumeration (JAVA的基本数据类型有8种:
byte(字节)、short(短整型)、int(整数型)、long(长整型)、float(单精度浮点数类型)、double(双精度浮点数类型)、char(字符类型)、boolean(布尔类型)
(5).注解类可以没有成员,没有成员的注解称为标识注解,例如JDK注解中的@Override、@Deprecation
(6).如果注解只有一个成员,并且把成员取名为value(),则在使用时可以忽略成员名和赋值号“=” ,例如JDK注解的@SuppviseWarnings ;如果成员名 不为value,则使用时需指明成员名和赋值号"=",
具体实例:
//定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public int age() default 20;
}
使用注解:
@MyAnnotation(name="aa",age=12)
//@MyAnnotation(name="aa")
public class MyClass {
}
解析注解
public class TestAnnotation {
public static void main(String[] args) {
getAnnotation();
}
public static void getAnnotation() {
MyAnnotation annotation = null;
Class<?> clazz = MyClass.class;
// 判断注解是否存在
boolean isPresent = clazz.isAnnotationPresent(MyAnnotation.class);
if (isPresent) {
// 获取注解
annotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
System.out.println("annotation=" + annotation);
// 获取注解中属性的值
String name = annotation.name();
int age = annotation.age();
System.out.println("name=" + name + ",age=" + age);
} else {
System.out.println("Annotation is not present");
}
}
}
除此之外,自定义的注解还可以在字段上,方法上使用。非常灵活。
总结
注解的内容远远不止这些,在框架中注解更有着非常多的使用,还需要在好好的学习,研究。