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注解的信息,有了这些信息,就可以搞事情了。

 

 

 

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载与列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 和适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager 和 CursorLoader,这能更好地管理数据加载,避免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建与定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值