Java 元注解学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/magi1201/article/details/82629247

注解,通常被理解为注释、标识,我觉得注解可以理解为修饰。

即被注解标注的类、变量、方法等,是为了达到某一个特定的效果。

Java中的元注解有4个,@Target,@Retention,@Documented和@Inherited。元注解可以理解为注解的注解,顾名思义,修饰注解的注解。

@Target

target定义注解出现的地方,换句话说,说明注解修饰的对象,这里的值均已枚举的方式出现。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

参考Target注解源码,返回的是一个枚举类型数组,里面定义了枚举可以返回的值类型

public enum ElementType {
    /** 类,接口(包括注解类型)或enum声明 */
    TYPE,

    /** 域(属性信息)声明(包括 enum 实例) */
    FIELD,

    /** 方法(函数)声明 */
    METHOD,

    /** 常用参数声明 */
    PARAMETER,

    /** 构造方法声明 */
    CONSTRUCTOR,

    /** 局部变量声明 */
    LOCAL_VARIABLE,

    /** 注解声明 */
    ANNOTATION_TYPE,

    /** 包声明 */
    PACKAGE,

    /** 参数类型声明 */
    TYPE_PARAMETER,

    /** 类型的使用 */
    TYPE_USE
}

以上是@Target可以使用的枚举值

@Retention

retention标注注解的保留范围,有源码、编译类和运行时三个范围

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

参考上面的注释,可以看到,Retention注解反馈一个保留策略结果,继续看RetentionPolicy源码

public enum RetentionPolicy {
    /** 被编译器丢弃,注解仅留在源码中,即注解不会编译到class文件中 */
    SOURCE,

    /** 注解被编译器记录在class文件中,但是不会保留到运行期。这个是保留策略的默认行为 */
    CLASS,

    /** 注解被编译器记录在class文件中,并被Java虚拟机在运行期保留,可以被反射读到 */
    RUNTIME
}

三个保留策略的保留范围 SOURCE < CLASS < RUNTIME

扫描二维码关注公众号,回复: 3848615 查看本文章

@Documented

documented注解修饰的元素可以被 javadoc 类的工具文档化。它代表着此注解会被javadoc工具提取成文档,在doc文档中的内容会因为此注解的信息内容不同而不同。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited

inherited注解修饰的类,子类可以继承父类中的注解。即拥有此注解的元素其子类可以继承父类的注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

示例:

这里有三个类,工作注解WorkAnnotation.java,工作类Work.java 和测试主类 WorkTest.java

WorkAnnotation.java 注解定义类,定义三个属性:最大工作小时 maxWorkHour ,姓名最大长度maxNameLength 和 工作类型 workType。

package com.meta.annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 定义工作注解
 * @author Administrator
 */
@Retention(RetentionPolicy.RUNTIME) //JVM会保留这个注解。
@Target({FIELD, METHOD}) //这个元注解是说明这个注解的目标是用于方法的。
public @interface WorkAnnotation {

	// int型注解属性,最大工作时间。
    int maxWorkHour() default 8;
    
    // int型注解属性, 用户姓名最大长度
    int maxNameLength() default 10;
    
    // String型注解属性,工作类型
    String workType() default "";
}

工作主类 Work.java 工作主类中,用到两个@WorkAnnotation注解的属性,并附详细注释,加以说明

package com.meta.annotation;

import java.lang.reflect.Method;

/**
 * 工作主类
 * 注解的具体应用
 * @author Administrator
 */
public class Work {

	@WorkAnnotation(maxWorkHour = 7)
	public void setMaxWorkHour(int maxHour)throws SecurityException, NoSuchMethodException{
	    // 获取当前method对象
        Class<? extends Work> clazz = this.getClass();
        Method method = clazz.getDeclaredMethod("setMaxWorkHour",int.class);
        
        // 判断当前方法是否有使用@WorkAnnotation注解
        if(method.isAnnotationPresent(WorkAnnotation.class)){

            // 通过method方法对象来获取@WorkAnnotation注解,并获取注解值
        	WorkAnnotation wa = method.getAnnotation(WorkAnnotation.class);
            int maxWorkHour = wa.maxWorkHour();
            
            // 注解值具体用法判断
            if(maxHour > maxWorkHour) {
                throw new RuntimeException("最大的工作时间为"+ maxWorkHour + "小时。");
            }
            System.out.println("工作时间设置成功,为" + maxHour + "小时。");
        }
	}
	
	@WorkAnnotation(maxNameLength = 10)
	public void setUsername(String username) throws NoSuchMethodException, SecurityException {
		Class<? extends Work> clazz = this.getClass();
		Method method = clazz.getDeclaredMethod("setUsername", String.class);
        if(method.isAnnotationPresent(WorkAnnotation.class)){
        	WorkAnnotation wa = method.getAnnotation(WorkAnnotation.class);
            int maxNameLength = wa.maxNameLength();
            if (username == null || username == "") {
	    		System.out.println("username设置失败,username 值为空");
	    	} else if (username.length() <= maxNameLength) {
	        	System.out.println("username设置成功,username = " + username);
	        } else {
	        	throw new RuntimeException("username最大程度为" + maxNameLength + ",实际长度为" + username.length());
	        }
	    }
	}
}

WorkTest.java 测试类

package com.meta.annotation;

public class WorkTest {

	public static void main(String[] args) throws SecurityException, NoSuchMethodException {
		 Work work = new Work();
	     work.setMaxWorkHour(9);
	     work.setUsername("zhangsan");
	}
}

Work.java中,setMaxWorkHour方法上面,注解@WorkAnnotation(maxWorkHour = 7) 属性值是7,这个7会覆盖掉WorkAnnotation.java 中默认的8,运行WorkTest.java 

会抛出异常 ,是因为设置的值和注解的值冲突了

修改设置的值为6,成功运行成功

maxNameLength属性的测试方法和maxWorkHour类似,不再重复描述了。

上面是最近几天看注解的一点整理,如有不当支持,欢迎留言批评斧正。谢谢。

猜你喜欢

转载自blog.csdn.net/magi1201/article/details/82629247