【Java】——Java中使用自定义注解(Annotation)

前言

    本文主要讲解自定义注解过程中需要用到的内容,以及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使用注解。

猜你喜欢

转载自blog.csdn.net/jiadajing267/article/details/80994885