枚举类与注解 之 注解讲解
注解:
在实际的开发过程中我们会经常使用到注解,如果在开发过程中你不懂注解,那么说明你不是一名合格的程序员。所以我们有必要对注解进行深入的了解。
Annotation可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotaion的“name=value”对中。
jdk内置了三个基本的注解:@Override @Deprecated @SuppressWarnings
我们在学习JAVA基础的时候,经常使用到的注解有:
@Override 告诉编译器这个方法是覆盖父类的方法
@WebServlet("/test") 表示某个类是一个Servlet,Web容器就会识别这个注解,在运行的时候调用它。
@Controller("/test") 表示某个类是一个控制器,告诉spring框架该类是一个控制器。
注解和注释是完全不同的两个东西,看起来有点类似,其实完全不同,注解会影响程序的运行。注释是给开发人员看的,不会影响程序的编译和运行。注解并不是给开发人员看的,是用于给程序看的,会影响程序的编译和运行,比如给编译器、tomcat、框架看的。
1.1注解的作用范围
自定义开发一个web容器,基本功能是加载servlet,需要管理它的生命周期,所以必须先识别程序中的哪些类是Servlet。程序启动的时候,扫描所有的类,找出添加了@WebServlet注解的类,进行加载(类似于spring IOC容器的启动过程)。
@WebServlet 是在程序运行的时候起作用的,那么JAVA就把他的作用范围规定为RUNTIME.
@Override 是给编译器看到饿,编译器工作的时候识别出包含了@Override 注解的方法,就去检查他上层父类的相应方法,存在则通过,否则报错。
@Override是编译的时候起作用,JAVA就把他的作用范围规定为SOURCE.
@Test 是生成测试代码,一般在框架中使用的比较多,作用范围是SOURCE.
JDK5.0提供了4个标准的meta-annotaion类型的元注解,分别是:target retention documented inherited
1.2@Target 指定注解针对的地方
ElementType:
ElementType.TYPE : 针对类 、接口
ElementType.FIELD : 针对成员变量
ElementType.METHOD: 针对成员方法
ElementType.PARAMETER : 针对方法参数
ElementType.CONSTRUCTOR: 针对构造器
ElementType.PACKAGE:针对包
ElementType.ANNOTATION: 针对注解
1.3 @Retention 指定注解的保留域
也可以理解为注解的存活时间
RetentionPolicy:
RetentionPolicy.SOURCE 源代码级别,由编译器处理,处理之后就不再保留
RetentionPolicy.CLASS 注解信息保留到类对应的class 文件中,这是一个默认行为,也就是说,如果不进行指定的时候,默认就是他。
RetentionPolicy.RUNTIME 由JVM读取,运行的时候使用,也就是说,只有声明为runtime声明周期的注解,才能通过反射进行获取。
1.4@Documented:(在实际的使用中比较少)
用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档,默认情况下,javadoc是不包括注解的。
定义为Documented的注解必须设置Retention 值为 RUNTIME.
1.5@Inherited:(在实际的使用中比较少)
被他修饰的Annotation将具有继承性。如果某个类使用了被该@Inherited修饰的Annotation,则其子类将自动具有该注解。
比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以继承父类级别的注解。
实际应用中,使用较少
1.6自定义注解
package com.annotationpractice;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//添加源注解,用来指明当前的注解是干什么用的
@Target(ElementType.METHOD)//表示这个注解只能添加到方法上面
@Retention(RetentionPolicy.RUNTIME)//表示该注解只能在运行的时候进行调用
public @interface InitMethod {
}
package com.annotationpractice;
public class InitDemo {
@InitMethod
public void init(){
System.out.println("init......");
}
public void test(){
}
}
package com.annotationpractice;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试注解的使用
*/
public class Test {
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> clazz = Class.forName("com.annotationpractice.InitDemo");
Method[] methods = clazz.getMethods();
if(null != methods){
for (Method method : methods) {
boolean flagInitMethod = method.isAnnotationPresent(InitMethod.class);//看看该方法中有没有该注解
if(flagInitMethod){
method.invoke(clazz.getConstructor(null).newInstance(null),null);
}
}
}
}
}
运行结果:init......
注意:自定义注解必须配上信息处理流程才有意义。也就是说必须要使用反射的方式。
1.7 jdk8中注解的新特性 可重复注解 类型注解
可重复注解
①在MyAnnotation上声明@Repetable,成员值为MyAnnotations.class
②MyAnnotation的Target和Retention等元注解与MyAnnotations相同
jdk8之前写该注解:
////这是在jdk8之前的写法
//@MyAnnotations({@MyAnnotation(value = "hi"),@MyAnnotation(value = "abc")})
jdk8写该注解:
@MyAnnotation(value = "abc")
@MyAnnotation(value = "hi")
package com.annotationpractice;
import com.sun.deploy.security.ValidationState;
import java.lang.annotation.*;
import java.lang.reflect.Type;
import static java.lang.annotation.ElementType.*;
/**
* 自定义注解
*/
@Repeatable(MyAnnotations.class)
@Target({TYPE,FIELD,METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String[] value() default "hello";
}
package com.annotationpractice;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* 自定义注解
*/
@Target({TYPE,FIELD,METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
package com.annotationpractice;
/**
* 如何自定义注解 参照@suppresswarning定义
* 1.注解声明为 @interface
* 2.内部定义成员,通常使用value表示
* 3.可以指定成员的默认值,使用default定义
* 4.如果自定义注解没有成员,表明是一个标识作用
*
*/
//@MyAnnotation(value = "hi") //当然这里可以不指定,也是可以的
////这是在jdk8之前的写法
//@MyAnnotations({@MyAnnotation(value = "hi"),@MyAnnotation(value = "abc")})
@MyAnnotation(value = "abc")
@MyAnnotation(value = "hi")
public class Person {
private String name;
private int age;
// @MyAnnotation //因为在注解内部已经指定了值了,所以,这里如果没有特别的需要,也是可以不写值的。
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
类型注解
ElementType.TYPE_PARAMETER: 表示该注解能写在类型变量的声明语句中(如:泛型声明)
ElementType.TYPE_USE: 表示该注解能写在使用类型的任何语句中
package com.annotationpractice;
import com.sun.deploy.security.ValidationState;
import java.lang.annotation.*;
import java.lang.reflect.Type;
import static java.lang.annotation.ElementType.*;
/**
* 自定义注解
*/
@Repeatable(MyAnnotations.class)
@Target({TYPE,FIELD,METHOD,TYPE_PARAMETER,TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String[] value() default "hello";
}
package com.annotationpractice;
import java.lang.reflect.Array;
import java.util.ArrayList;
/**
* 类型注解
*/
public class Generic<@MyAnnotation T> {
public void show() throws @MyAnnotation RuntimeException{
ArrayList<@MyAnnotation String> list = new ArrayList<>();
int num=(@MyAnnotation int) 10L;
}
}
案例:简单的测试框架
参考网址:https://blog.csdn.net/zzu_seu/article/details/104673681