注解(Annotation),是源码中特殊的语法元数据,类、方法、变量、参数都可以被注解。利用注解可以标记源码以便编译器为源码生成文档和检查代码,也可以让编译器和注解处理器在编译时根据注解自动生成代码,甚至可以保留到运行时以便改变运行时的行为。
注解的保留位置:
这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码
注解作用目标:
自定义注解:
/**
* 定义类注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassInfo {
String value();
}
/**
* 定义字段注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldInfo {
int[] value();
}
/**
* 定义方法注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodInfo {
String name() default "默認值";
String data();
int age() default 100;
}
/**
* 使用注解
*/
@ClassInfo("测试类")
public class TestAnnotation {
@FieldInfo(value = {1, 2})
public String fieldA = "字段属性";
@FieldInfo(value = {100})
public int fieldB = 100;
@MethodInfo(name = "这是一个方法名字", data = "hello")
public static String getMethodA() {
return TestAnnotation.class.getSimpleName();
}
@MethodInfo(data = "hello2")
public static String getMethodB() {
return TestAnnotation.class.getSimpleName();
}
}
运行注解:
public class Test {
public static void main(String[] args) {
Class<TestAnnotation> cls = TestAnnotation.class;
ClassInfo classInfo = cls.getAnnotation(ClassInfo.class);
if (classInfo != null) {
System.out.println(cls);
System.out.println(classInfo);
System.out.println(classInfo.value());
}
System.out.println("---------------------");
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
FieldInfo fieldInfo = field.getAnnotation(FieldInfo.class);
if (fieldInfo != null) {
System.out.println(field);
System.out.println(fieldInfo);
System.out.println(Arrays.toString(fieldInfo.value()));
}
}
System.out.println("---------------------");
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
if (methodInfo != null) {
System.out.println(method);
System.out.println(methodInfo);
System.out.println(methodInfo.name());
System.out.println(methodInfo.data());
System.out.println(methodInfo.age());
}
}
}
}
输出信息:
class com.immersionstatusbar.test.TestAnnotation
@com.immersionstatusbar.test.ClassInfo(value=测试类)
测试类
---------------------
public java.lang.String com.immersionstatusbar.test.TestAnnotation.fieldA
@com.immersionstatusbar.test.FieldInfo(value=[1, 2])
[1, 2]
public int com.immersionstatusbar.test.TestAnnotation.fieldB
@com.immersionstatusbar.test.FieldInfo(value=[100])
[100]
---------------------
public static java.lang.String com.immersionstatusbar.test.TestAnnotation.getMethodA()
@com.immersionstatusbar.test.MethodInfo(name=这是一个方法名字, age=100, data=hello)
这是一个方法名字
hello
100
public static java.lang.String com.immersionstatusbar.test.TestAnnotation.getMethodB()
@com.immersionstatusbar.test.MethodInfo(name=默認值, age=100, data=hello2)
默認值
hello2
100
通常定义固定值可以直接使用枚举或static final
定义常量。
// 枚举
public enum TYPE_ENUM {
TYPE_A,
TYPE_B,
TYPE_C
}
// 常量
public class TYPE_CONSTANT {
public static final int TYPE_A = 1;
public static final int TYPE_B = 2;
public static final int TYPE_C = 3;
}
// 定义变量
// 取值只能为{TYPE_A,TYPE_B,TYPE_C}
TYPE_ENUM enumVar;
// 取值不受限制
int type;
为了解决上面的这些问题,Android提供一个有用的注解,简化枚举和常量
implementation 'com.android.support:support-annotations:25.2.0'
如:@IntDef
、@StringDef
等
public class Person {
public static final int TYPE_A = 1;//男
public static final int TYPE_B = 2;//女
public static final int TYPE_C = 3;//保密
// 定义一个注解
@IntDef({TYPE_A, TYPE_B, TYPE_C})
@interface Type {
}
//年齡限制:0-100
private int age;
//性別限制:男,女,保密
private int sex;
@Type
public int getSex() {
return sex;
}
public void setSex(@Type int sex) {
this.sex = sex;
}
public void setAge(@IntRange(from = 0, to = 100) int age) {
this.age = age;
}
@IntRange(from = 0, to = 100)
public int getAge() {
return age;
}
}
使用:
Person person = new Person();
person.setAge(18);
person.setAge(Person.TYPE_A);