定义注解

Java元注解详解及使用示例
/**
 * 注解定义
 * 要定义两个元注解(元注解:注解的注解)
 * @Target 
 * 参数为ElementType数组类型,如果有多个参数,就要定义在大括号{}里面
 * 主要参数:
 * 	TYPE(Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。)		 
 * 		类、接口(包括注释类型)或枚举声明 
 *  FIELD 			  
 *  	字段声明(包括枚举常量)
 *  METHOD    		  
 *      方法声明
 * @Retention
 * 参数为RetentionPolicy类型
 * 三个参数:
 *  SOURCE 
 *     编译器javac要丢弃的注释(只是提示给开发者,有@Override,@SuppressWarnings)。
 *  CLASS 
 *     编译器将把注释记录在类文件(.class)中,但在运行时 VM 不需要保留注释。 
 *  RUNTIME
 *	      编译器将把注释记录在类文件中(.class),在运行时 VM 将保留注释,因此可以反射性地读取
 *		(@deprecated,下次调用这个注解标注的方法还会提示这个类已经过时)。
 * @author dhh
 *
 */
@Target({ElementType.TYPE,ElementType.METHOD})   //只能定义在type(类,接口...)上和方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInnocation {
	/**
	 * 定义一个String返回型的属性
	 * 用注解的时候就要@MyInnocation(str="xxx")
	 * 打印效果:
	 * MyInnocation innocation = AnnocationTest.class.getAnnotation(MyInnocation.class);
	 * System.out.println(innocation.color());
	 * @return
	 */
	String color() default "green";  
	
	/**
	 * 整型
	 * @return
	 */
	int num() default 2;
	/**
	 * 看到有时@MyInnocation("xxx") 
	 * 当只有value这一个属性的时候,或者说有多个属性,但是
	 * 这些属性都定义了default,可以省略"属性名="
	 * 如果看到@MyInnocation()也不要奇怪,那是因为value属性也定义了default值
	 * @return
	 */
	String value();
	
	/**
	 * 枚举类型,定义在EnumImpl中的枚举
	 * @return
	 */
	EnumImpl.Sex sex() default EnumImpl.Sex.FEMALE; //默认为女性
	
	/**
	 * 定义返回类型为注解的属性
	 * 引用@MyInnocation(inno=@Override(""))
	 */
	//Override inno() ;
	
	/**
	 * 引用的时候如果一个值,可以直接@MyInnocation(nums=3.3f)
	 * 多个值nums={...}
	 * @return
	 */
	float[] nums() default {3.5f,3,3f};
}

<think>我们正在讨论如何在Java中定义注解并限制注解参数的取值范围。根据引用内容,特别是引用[2]和引用[4],我们可以使用@IntDef(对于整型)或@StringDef(对于字符串)等元注解来限定参数值的范围。此外,引用[1]提到如果注解有配置参数,则必须使用指定参数值,格式为“参数名=参数值”,并且如果只有一个参数且名称为value,可以省略“value=”。 步骤: 1. 定义注解:使用@interface定义一个新的注解类型。 2. 使用元注解:使用@Retention指定注解的保留策略(通常为SOURCE,因为这类注解主要用于编译时检查),使用@Target指定注解可以应用的位置(如参数、字段等)。 3. 限定取值范围:使用@IntDef(或其他类似注解)指定允许的取值,该元注解需要一个value参数,其值为允许的常量数组。 4. 定义常量:定义一组常量,这些常量将作为注解参数允许的值。 注意:在Android开发中,为了性能考虑(避免枚举带来的内存开销),推荐使用注解来限定整型或字符串参数。 示例:假设我们要定义一个注解@LogLevel,限定其值只能是几个特定的整数(代表日志级别)。 首先,定义常量类(或接口)来存放允许的值: ```java public class Level { public static final int LEVEL_V = 0; public static final int LEVEL_D = 1; public static final int LEVEL_I = 2; public static final int LEVEL_W = 3; public static final int LEVEL_E = 4; } ``` 然后,定义注解@LogLevel: ```java import static java.lang.annotation.RetentionPolicy.SOURCE; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; // 可以根据需要添加其他目标类型,比如方法、局部变量等 @Retention(SOURCE) // 注解只在源码级别保留,不编译到class文件中,也不在运行时保留 @Target({PARAMETER, FIELD}) // 可以用于参数和字段 @IntDef(value = {Level.LEVEL_V, Level.LEVEL_D, Level.LEVEL_I, Level.LEVEL_W, Level.LEVEL_E}) public @interface LogLevel { } ``` 这样,我们就可以在方法参数或字段上使用@LogLevel注解,并且只能使用Level类中定义的常量值。 使用示例: ```java public void setLogLevel(@LogLevel int level) { // ... } ``` 此时,如果调用setLogLevel方法时传入的值不是Level中定义的常量(比如传入5),IDE(如Android Studio)会给出警告或错误(取决于IDE配置)。注意,这只是在编译时进行静态检查,并不会在运行时强制检查(因为注解在运行时已经不存在了)。如果需要在运行时检查,需要自行编写验证逻辑。 另外,引用[1]中提到,如果注解只有一个参数且名称为value,可以省略“value=”。但在定义@IntDef时,我们只有一个value参数,所以我们可以直接写常量数组,不需要写“value=”。 对于字符串的限定,可以使用@StringDef,用法类似。 总结:通过使用@IntDef、@StringDef等元注解,我们可以为注解参数(或方法参数、字段)限定取值范围,从而在编译时提供类型安全的检查。 相关问题: 1. 如何为自定义注解定义多个参数? 2. 如何在运行时获取注解信息并进行验证? 3. 自定义注解的保留策略(RetentionPolicy)有哪些,分别适用于什么场景? 4. 除了参数和字段,自定义注解还可以应用在哪些目标上?</think>### Java注解参数值限定方法 在Java中定义注解并限定参数取值范围,主要通过元注解和常量定义实现。核心步骤如下: #### 1. **定义常量集合** ```java public class LogLevel { public static final int VERBOSE = 0; public static final int DEBUG = 1; public static final int INFO = 2; public static final int WARN = 3; public static final int ERROR = 4; } ``` #### 2. **创建自定义注解** ```java import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import androidx.annotation.IntDef; // 定义取值范围 @IntDef(value = { LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR }) // 指定注解保留策略(SOURCE表示仅编译期有效) @Retention(RetentionPolicy.SOURCE) // 定义定义注解 public @interface LogLevelAnnotation { int value() default LogLevel.INFO; // 默认值 } ``` #### 3. **使用注解限定参数** ```java public void setLogLevel(@LogLevelAnnotation int level) { // 方法实现... } // 正确用法 setLogLevel(LogLevel.DEBUG); // 错误用法(编译期警告) setLogLevel(99); // 超出限定范围的值 ``` #### 关键说明: 1. **`@IntDef` 元注解** 指定允许的整数值集合,结合常量定义实现范围限定[^2][^4]。 2. **保留策略 `@Retention(SOURCE)`** 注解仅在源码级别有效,不增加运行时开销[^2][^3]。 3. **参数命名规则** 若唯一参数名为 `value`,使用时可直接赋值:`@LogLevelAnnotation(LogLevel.ERROR)`[^1]。 4. **替代枚举的优势** 避免枚举的内存开销(尤其在Android开发中),同时保持类型安全[^4]。 #### 完整示例: ```java // 定义常量 public class NetworkType { public static final int WIFI = 1; public static final int MOBILE = 2; public static final int ETHERNET = 3; } // 自定义注解 @IntDef({NetworkType.WIFI, NetworkType.MOBILE, NetworkType.ETHERNET}) @Retention(RetentionPolicy.SOURCE) public @interface NetworkTypeAnnotation {} // 使用注解 public void connect(@NetworkTypeAnnotation int type) { switch (type) { case NetworkType.WIFI: // 处理WiFi连接 break; case NetworkType.MOBILE: // 处理移动网络 break; } } ``` > **注意事项**: > - 此方案依赖IDE或编译器的静态检查(如Lint) > - 运行时无强制验证,需配合代码规范使用[^2][^4] > - 支持 `@StringDef` 实现字符串限定(原理相同) --- ### 相关问题 1. 如何在运行时获取注解参数值? 2. `@IntDef` 和枚举类型在性能上有何差异? 3. 如何为自定义注解设置多个参数? 4. 注解的 `@Target` 元注解有哪些使用场景? 5. 如何在Kotlin中实现相同的参数限定? [^1]: Java - 自定义注解。规则2:如果注解含有配置参数,则必须使用指定参数值。格式:“参数名 = 参数值”,如果只有一个参数成员,且名称为value,可以省略“value=” [^2]: Java学习 使用注解将参数的值限定。使用@IntDef限定整数值范围,@Retention(SOURCE)表示注解仅在编译期有效 [^3]: Java中的注解,自定义注解。元注解用于修饰其他注解 [^4]: Java参数注解。使用注解替代枚举限定参数值,避免内存开销
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值