java注解

本文深入解析Java中的注解功能,包括定义、使用范围、保留策略及如何通过反射访问注解信息,提供实例演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java中的Annotation功能可用于类、构造方法、普通方法、成员变量(全局变量)、参数等声明中。该功能不影响程序的正常运行。

定义Annotation

基本语法:

定义Annotation的关键字是@interface

@Target(ElementType.METHOD)//表示该注解只能用于方法
//................还可以有其它设置
public @interface Lock {

	/**
	 * 遵循接口(interface)规范,使用默认的权限修饰符,不要显示声明public等
     * String 称为成员类型
	 * 注解中的成员类型只能是基本数据类型、String、Class、注解(annotation)、枚举
	 * 或者它们的一维数组类型。比如Integer是不支持的。
	 * 
	 * value 称为成员名称,命名符合java命名要求即可。
	 * 假如在自定义注解中只有一个成员,通常都命名为value。
	 * 
	 * 这里应该理解为方法,不能理解为属性,所以成员名称后面是带括号()的。
	 * */
	String value();
	
	/**
	 * 在声明自定义注解成员的时候可以给定一个默认值
	 * */
	int expire() default 5;
	
	Class<String> type() default String.class; 
}

@Target设置(该注解被设置为只能用于Annotation)

@Target设置用来设置Annotation类型适用的程序元素种类(即限制注解使用的范围,如果未设置@Target,则表示不限制使用范围)。

@Target注解中定了一个成员ElementType的一维数组类型,用来设置@Target,是一个枚举类。所有属性如下:

枚举常量说明
ANNOTATION_TYPE表示只能用于注解
TYPE表示用于类、接口和枚举,以及Annotation类型
CONSTRUCTOR表示用于构造方法
FIELD表示用于成员变量和枚举常量
METHOD表示用于方法
PARAMETER表示用于参数
LOCAL_VARIABLE表示用于局部变量
PACKAGE表示用于包
TYPE_PARAMETERjdk1.8以后提供,用于泛型
TYPE_USEjdk1.8以后提供,用于任意类类型

基本用法:

@Target(value= {ElementType.METHOD, ElementType.FIELD})//@Target注解中定义的成员ElementType是枚举的一维数组类型
@Target(ElementType.METHOD)//如果只需要单个,缩写指定单个属性即可
public @interface Lock {

    //..................成员

}

@Retention设置(该注解被设置为只能用于Annotation)

@Retention设置Aannotation的有效范围。成员RetentionPolicy是一个枚举类型,用来设置@Retention。所有属性如下:

枚举常量说明
SOURCE表示不编译Annotaion到类文件中,有效范围最小
CLASS表示编译Annotation到类文件中,但在运行时不加载Annotation到JVM中
RUNTIME表示在运行时加载Annotation到JVM中,有效范围最大

基本用法:

@Retention(RetentionPolicy.RUNTIME)
public @interface Lock {

    //..................成员

}

@Documented设置

Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。

基本用法:

@Documented
public @interface Lock {
    
    //.......成员变量
}

@Inherited设置

表示该注解会被子类继承,注意,仅针对类,成员属性、方法并不受此注释的影响。对于类来说,子类要继承父类的注解需要该注解被 @Inherited 标记。

基本用法:

@Inherited
public @interface Lock {

    //..........成员

}

简单示例

1、定义一个用来注解构造方法的Annotation,只有一个类型为String的成员,有效范围在运行时加载到jvm中。

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constructor_Annotation {

 	String value() default "默认的构造方法";
}

2、定义一个用来注解成员属性、方法和参数的Annotation,有效范围在运行时加载到jvm中。

@Target(value= {ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Fiel_Method_Parameter_Annotation {

	String describle();
	
	Class type() default void.class;
}

3、编写一个类Record,在该类中运用前面定义的Annotation对构造方法、字段、方法和参数进行注解。

public class Record {

	@Fiel_Method_Parameter_Annotation(describle="编号", type=int.class)
	private int id;
	
	@Fiel_Method_Parameter_Annotation(describle="姓名", type=String.class)
	private String name;

	@Constructor_Annotation//该注解成员value给了默认值"默认的构造方法" //注解构造方法
	public Record() {
		super();
	}

	@Constructor_Annotation(value="有参构造方法")
	public Record(@Fiel_Method_Parameter_Annotation(describle="编号", type=int.class)int id, //注解参数
			@Fiel_Method_Parameter_Annotation(describle="姓名", type=String.class)String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Fiel_Method_Parameter_Annotation(describle="获取编号", type=int.class)//注解方法
	public int getId() {
		return id;
	}

	@Fiel_Method_Parameter_Annotation(describle="设置编号")
	public void setId(@Fiel_Method_Parameter_Annotation(describle="编号", type=int.class)int id) {//注解参数
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

访问Annotation信息(通过反射读取)

如果再定义Annotation时,将@Retention设置为RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的Annotation信息,如获取构造方法、字段和方法的Annotation信息。

类Constructor<T>、Field、Method均继承自AccessibleObject,在AccessibleObject类中定义了3个关于Annotation的方法。

方法说明
isAnnotationPresent(Class<? extends Annotation> annotationClass)用来查看是否添加了指定类型的Annotation,有返回true,否则返回false
getAnnotation(Class<T> annotationClass)用来获取指定类型的Annotation,如果不存在返回null
Annotation[] getAnnotations()获取目标多有的Annotation,返回的是一个数组

在Constructor<T>、和Method中还单独定义了Annotation[][] getParameterAnnotations()方法,用来获取为多有参数添加的Annotation,将以Annotation的二维数组返回,在数组中的顺序与声明的顺序相同,如果没有参数则返回一个长度为0的数组;如果存在未添加Annotation的参数,将用一个长度为0的嵌套数组占位。

简单的示例

沿用上面的Record类。

public class Test {

	public static void main(String[] args) {
		
		Record record = new Record();
		Class<? extends Record> recordClass = record.getClass();
		
		//获取目标对象的所有属性
		Field[] fields = recordClass.getDeclaredFields();
		for(int i=0;i<fields.length;i++) {
			Field field = fields[i];
			if(field.isAnnotationPresent(Fiel_Method_Parameter_Annotation.class)) {
				Fiel_Method_Parameter_Annotation fiel_Method_Parameter_Annotation = field.getAnnotation(Fiel_Method_Parameter_Annotation.class);
				System.out.println("成员属性描述 :" + fiel_Method_Parameter_Annotation.describle());
				System.out.println("成员属性类型 :" + fiel_Method_Parameter_Annotation.type());
			}
		}
		
		//获取目标对象的所有构造方法
		Constructor<?>[] constructors = recordClass.getDeclaredConstructors();
		for(int i=0; i<constructors.length; i++) {
			Constructor<?> constructor = constructors[i];
			if(constructor.isAnnotationPresent(Constructor_Annotation.class)) {
				Constructor_Annotation constructor_Annotation = constructor.getAnnotation(Constructor_Annotation.class);
				System.out.println(constructor_Annotation.value());//打印目标类上的@Constructor_Annotation注解的value()成员
			}
			
			Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
			for(int j=0; j<parameterAnnotations.length; j++) {
				int length = parameterAnnotations[j].length;//获取指定参数注解的长度
				if(length == 0) {//表示没有添加Annotation的参数
					System.out.println("没有添加Annotation的参数");
				}else {
					for(int k=0; k<length; k++) {
						Fiel_Method_Parameter_Annotation fiel_Method_Parameter_Annotation = (Fiel_Method_Parameter_Annotation) parameterAnnotations[j][k];
						System.out.println("参数描述 : " + fiel_Method_Parameter_Annotation.describle());
						System.out.println("参数类型 : " + fiel_Method_Parameter_Annotation.type());
					}
				}
			}
		}
		
		//获取目标对象的方法
		Method[] methods = recordClass.getDeclaredMethods();
		for(int i=0;i<methods.length;i++) {
			Method method = methods[i];
			if(method.isAnnotationPresent(Fiel_Method_Parameter_Annotation.class)) {
				Fiel_Method_Parameter_Annotation fiel_Method_Parameter_Annotation = method.getAnnotation(Fiel_Method_Parameter_Annotation.class);
				System.out.println("方法描述 :" + fiel_Method_Parameter_Annotation.describle());
				System.out.println("方法返回类型 :" + fiel_Method_Parameter_Annotation.type());
			}
			
			Annotation[][] parameterAnnotations = method.getParameterAnnotations();
			for(int j=0;j<parameterAnnotations.length;j++) {
				int length = parameterAnnotations[j].length;
				if(length == 0) {//表示没有添加Annotation的参数
					System.out.println("没有添加Annotation的参数");
				}else {
					for(int k=0;k<length;k++) {
						Fiel_Method_Parameter_Annotation fiel_Method_Parameter_Annotation = (Fiel_Method_Parameter_Annotation) parameterAnnotations[j][k];
						System.out.println("参数描述 : " + fiel_Method_Parameter_Annotation.describle());
						System.out.println("参数类型 : " + fiel_Method_Parameter_Annotation.type());
					}
				}
			}
		}
	}
}

结果:

成员属性描述 :编号
成员属性类型 :int
成员属性描述 :姓名
成员属性类型 :class java.lang.String
默认的构造方法
有参构造方法
参数描述 : 编号
参数类型 : int
参数描述 : 姓名
参数类型 : class java.lang.String
方法描述 :获取编号
方法返回类型 :int
没有添加Annotation的参数
方法描述 :设置编号
方法返回类型 :void
参数描述 : 编号
参数类型 : int

总结

利用Annotation功能,可以对类、构造方法、属性(成员变量)、方法、参数等进行注解,在程序运行时通过反射可以获取被Annotation注解的信息,有了这些信息,就可以搞事情了。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值