自定义注解

带你学习自定义注解

1.1注解

自定义注解主要是在jdk1.5之后提供的一种语法,其主要作用是编译检查(比如@override)和代码分析(通过代码中添加注解,利用注解解析器对添加了注解的代码进行分析,获取想要的结果,一般自定义的注解都是这一种功能)。

1.2常用的jdk的注解

JDK提供的注解最常用的是3个,@Override,@Deprecated和@SuppressWarnings.
@Override:最常见的注解之一了,表示子类重写了父类的方法,或者实现了接口的方法
@Deprecated:表示是已经过期,建议换个方法,使用的话该方法会被编辑器画一条横线,表示已经弃用。
@SuppressWarnings:表示抑制警告的意思。比如我们新建一个变量,但是没有用他,编辑器会提示,该变量没有使用,但是如果添加@SuppressWarnings相关注解就不会提示了

2.0自定义注解

除了使用java自带的注解以外,我们也可以自己定义注解来使用,代码过程中,注解是一个很方便的东西,比如:权限控制,日志记录等等。

2.0自定义注解的基本语法

1.定义一个注解和定义接口类似,只不过是在interface前边加@符号,在它的内部可以添加属性值
2.修饰符 返回值类型 属性名() [default value]
3.其中,修饰符只能使用public和abstract,返回值类型使用基本类型、数组、枚举,字符串、注解都可以使用,但是注意,数组要是一维数组
4.要定义自定义注解,还要使用元注解,用于修饰自定义注解,一般的话会使用三种
@Retention、@Target、@Documented
(下边给大家解释这三个分别是什么意思)

2.1@Retention注解

@Retention:表示的是这个注解的生命周期,其中有三个枚举变量可以选择
1.RetentionPolicy.SOURCE:表示的是该类在编译为字节码时便弃掉
2.RetentionPolicy.CLASS:表示为该注解被编译为字节码之后被虚拟机加载完后弃掉
3.RetentionPolicy.RUNTIME:表示该注解的可见范围是多少,这里给的是RUNTIME运行时都可见,大部分时候使用的也都是RUNTIME,因为RUNTIME可以通过反射得到该注解的信息。

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * SOURCE级别表示代码级别可见,经过编译器编译生成字节码对象时,此注解就没了。
     * 比如@override就是代码级别可见
     */
    SOURCE,  

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * CLASS表示字节码对象级别可见,但是字节码对象被虚拟机加载时,
     * 这个注解会被抛弃,这是默认的可见级别
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     * RUNTIME表示运行时也可见,当虚拟机加载字节码对象时,此注解仍然可见。
     * 因此可以通过反射获取注解信息,然后完成相应的注解解析工作,一般自定义的注解都是运行时可见。
     */
    RUNTIME
}

2.2@Target注解

@Target:用于修饰此注解可以用于什么类型上。比如注解可以用在类级别、方法、成员字段或者构造函数上。那么它自然也有枚举变量可以选择。
	1.METHOD:使用在方法上
   		2.FIELD:使用在变量上
   		3.TYPE:使用在类上
   		4.CONSTRUCTOR:使用在构造函数上
   		5.PACKAGE:使用在包上
   		6.PARAMETER:使用在方法参数上
   		7.LOCAL_VARIABLE:使用在局部变量上
   		8.ANNOTATION_TYPE:使用在注解上的注解
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration 可以修饰类*/
    TYPE,  

    /** Field declaration (includes enum constants) 可以修饰字段*/
    FIELD,

    /** Method declaration 可以修饰方法*/
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration 构造方法*/
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

2.3@Documented注解

@Documented:表示该注解可以写入javadoc中

3.0下边上代码

上面这个注解定义说明此注解可以用在类,方法和成员地段上。是运行时可见的,其内有一个属性,默认值是“苹果”。

import java.lang.annotation.*;

/**
 * Target:(表示该注解可以使用在方法,类,变量上)
 *      1.METHOD:使用在方法上
 *      2.FIELD:使用在变量上
 *      3.TYPE:使用在类上
 *      4.CONSTRUCTOR:使用在构造函数上
 *      5.PACKAGE:使用在包上
 *      6.PARAMETER:使用在方法参数上
 *      7.LOCAL_VARIABLE:使用在局部变量上
 *      8.ANNOTATION_TYPE:使用在注解上的注解
 *      (其实多用用就会发现注解特别方便快捷~~~~多练习吧)
 * Documented:表示该注解可以写入javadoc中
 * Retention:
 *      1.RUNTIME:表示该注解的可见范围是多少,这里给的是RUNTIME运行时都可见,大部分时候使用的也都是RUNTIME,因为RUNTIME可以通过反射得到该注解的信息
 *      2.SOURCE:表示的是该类在编译为字节码时便弃掉
 *      3.CLASS:表示为该注解被编译为字节码之后被虚拟机加载完后弃掉
 */
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {

    public String value() default "苹果";
}

然后我们定义一种叫苹果的水果。其内部有个成员变量appleName。我们在这个成员字段上加上@FruitName注解。

package me.gacl.annotation.entity;

import me.gacl.annotation.anno.FruitName;

public class Apple {

    @FruitName(value = "草莓")
    private String fruitName;
}

3.1关于自定义注解的解析

上面提到,自定义的注解需要定义注解的可见范围。一般我们都定义为运行时可见。因此,通过反射,我们可以拿到注解的内容。通过反射拿到代码的注解内容,进行相关的逻辑处理工作,以达到注解的目的。
通过反射获得注解内容的常用方法有

T getAnnotation(Class) : 获得当前对象的指定的注解。
Annotation[] getAnnotations() X: 获得当前对象的所有注解
boolean isAnnotationPresent(annotationClass): 当前对象是否有注解
getDeclaredMethods():获取这个类中的所有方法
getDeclaredFields():获取这个类中所有的属性(包括私有属性)
getFeilds():获取这个类中所有的属性(不包括私有属性)

package me.gacl.annotation.common;

import me.gacl.annotation.anno.FruitName;
import me.gacl.annotation.entity.Apple;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class FruitUtil {

    public static void main(String[] args) {
        FruitUtil.getInfomation(Apple.class);
    }

    /**
     * 该方法通过java的反射机制获取类中的注解信息,
     * @param tClass Class<?>作为参数表示可以传入任意对象
     */
    public static void getInfomation(Class<?> tClass){

        //获取到该类中的所有属性,其实也可以通过getFields()获取属性,但是通过getFeilds获取不到类中private修饰的属性信息
        Field[] fields=tClass.getDeclaredFields();
        //这个便是获取该类中的所有方法
        Method[] methods=tClass.getDeclaredMethods();

        for (Field field :fields) {
            //判断如果该字段含有FruitName注解的信息
            if(field.isAnnotationPresent(FruitName.class)){
                //获取该字段上注解的信息
                FruitName fruitName=field.getAnnotation(FruitName.class);
                //输出该注解的的信息
                System.out.println(fruitName.value());
            }
        }
    }
}

最后运行结果为:

"C:\Program Files\Java\jdk1.8.0_141\bin\java.exe" "-javaagent:C:\Installation\IntelliJ IDEA 2018.1.6\lib\idea_rt.jar=65037:C:\Installation\IntelliJ IDEA 2018.1.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_141\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\rt.jar;C:\personalExpansion\Annotation\target\classes;C:\work\repository\org\springframework\boot\spring-boot-starter\2.1.0.RELEASE\spring-boot-starter-2.1.0.RELEASE.jar;C:\work\repository\org\springframework\boot\spring-boot\2.1.0.RELEASE\spring-boot-2.1.0.RELEASE.jar;C:\work\repository\org\springframework\spring-context\5.1.2.RELEASE\spring-context-5.1.2.RELEASE.jar;C:\work\repository\org\springframework\spring-aop\5.1.2.RELEASE\spring-aop-5.1.2.RELEASE.jar;C:\work\repository\org\springframework\spring-beans\5.1.2.RELEASE\spring-beans-5.1.2.RELEASE.jar;C:\work\repository\org\springframework\spring-expression\5.1.2.RELEASE\spring-expression-5.1.2.RELEASE.jar;C:\work\repository\org\springframework\boot\spring-boot-autoconfigure\2.1.0.RELEASE\spring-boot-autoconfigure-2.1.0.RELEASE.jar;C:\work\repository\org\springframework\boot\spring-boot-starter-logging\2.1.0.RELEASE\spring-boot-starter-logging-2.1.0.RELEASE.jar;C:\work\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\work\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\work\repository\org\apache\logging\log4j\log4j-to-slf4j\2.11.1\log4j-to-slf4j-2.11.1.jar;C:\work\repository\org\apache\logging\log4j\log4j-api\2.11.1\log4j-api-2.11.1.jar;C:\work\repository\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;C:\work\repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;C:\work\repository\org\springframework\spring-core\5.1.2.RELEASE\spring-core-5.1.2.RELEASE.jar;C:\work\repository\org\springframework\spring-jcl\5.1.2.RELEASE\spring-jcl-5.1.2.RELEASE.jar;C:\work\repository\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;C:\work\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar" me.gacl.annotation.common.FruitUtil
草莓

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值