前言
本文主要讲解自定义注解过程中需要用到的内容,以及Java中自定义注解。在以下的讲解中如有理解偏颇之处,恳请各位大神指正,小编不胜感激!
如果有不清楚什么是注解的朋友,请先认识注解【从零学Java】——认识Annotation注解
注解语法
注解通过@interface关键字修饰
public @interface TestAnnotation {
}
注解应用
@TestAnnotation
public class Test {
}
元注解
为了让注解能够正常的工作还需要元注解。何为元注解,就是可以注解到注解上的注解。元注解有@Retention,@Documented,@Target,@Inherited,@Repeatable。
@Retention
当@Retention应用到一个注解上的时候,解释说明了这个注解的生命周期
RetentionPolicy.SOURCE | 注解只保留在源码阶段,编译时编译器会将它丢弃 |
RetentionPolicy.CLASS | 注解只保留在编译进行的时候,不会被加载到JVM中 |
RetentionPolicy.RUNTIME | 注解可以保留到程序运行时,会被加载到JVM中,程序运行时可以获取得到 |
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
@Documented
将注解中的元素包含到Javadoc中。生成Javadoc文件中有显示修饰的注解(前提注解被元注解@Documented修饰)
@Documented
public @interface TestAnnotation {
}
@Target
注解运用的地方,注解被运用的类型
ElementType.ANNOTATION_TYPE | 给一个注解进行注解 |
ElementType.CONSTRUCTOR | 给构造方法进行注解 |
ElementType.FIELD | 给属性进行注解 |
ElementType.LOCAL_VARIABLE | 可以给局部变量进行注解 |
ElementType.METHOD | 可以给方法进行注解 |
ElementType.PACKAGE | 可以给包进行注解 |
ElementType.PARAMETEP | 可以给一个方法内的参数进行注解 |
ElementType.TYPE | 可以给一个类型进行注解,比如类,接口,枚举等 |
@Target(ElementType.TYPE)
public @interface TestAnnotation {
}
@Inherited
可以被子类继承的注解,如果超类中用@Inherited修饰,那么子类可以继承父类中的注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
@Repeatable
在Java8中被加入,允许同一个注解可以被多次运用到同一个类型上。
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。
何为容器注解?
用来存放其他注解的地方,它本身也是注解
注解的提取
虽然自定义了注解,但是怎样才能让自定义注解在程序中发挥我们想要的作用呢?反射就是我们必备的手段。
//注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
//然后通过 getAnnotation() 方法来获取 Annotation 对象
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
//是 getAnnotations() 方法
public Annotation[] getAnnotations() {}
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解
注解的作用
官方文档
注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。
注解有许多用处,主要如下:
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取
注意:注解不是代码本身的一部分,注解主要针对编译器和其他工具软件。
当开发者使用Annotation修饰了类,方法等内容,这些Annotation不会自己生效,必须有开发者提供相应的代码提取并处理Annotation信息。这些处理提取和处理Annotation的代码统称为APT(Annotation Processing Tool)。
一般自定义注解是为了完成某个目的,最常用就是记录操作日志。但是这个过程又是怎么完成的呢?
Java中自定义注解的使用
自定义注解
package com.jia.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 贾文静 on 2018/7/11.
* Describe
*/
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String msg() default "";
}
使用注解的类
package com.jia.annotation;
public class Hello {
@MyAnnotation(msg = "sayHello方法")
public void sayHello(String name,String start) {
System.out.println("hello "+name);
System.out.println(start);
}
}
反射调用
package com.jia.annotation;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @author 贾文静 on 2018/7/11.
* Describe
*/
public class AnnotationTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Hello hello = new Hello();
Class clazz = hello.getClass();
Method method = clazz.getMethod("sayHello", String.class, String.class);
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println(annotation.msg());
}
method.invoke( hello,"jia","world");
}
总结
注解在现在程序开发中发挥巨大的加载,学会自定义注解以及相关的使用也是必备技能了。在下篇博客小编会给实现利用CGLIB动态代理+注解对参数合法性进行判断,以及spring中注解的使用,还有利用aop使用注解。