Android 注解基本使用

文章目录

      • Android注解基本使用
          • 内置注解
          • @Retention
          • @Target
        • Java自定义注解
        • Android中注解替代枚举/常量

Android注解基本使用

注解(Annotation),是源码中特殊的语法元数据,类、方法、变量、参数都可以被注解。利用注解可以标记源码以便编译器为源码生成文档和检查代码,也可以让编译器和注解处理器在编译时根据注解自动生成代码,甚至可以保留到运行时以便改变运行时的行为。

内置注解
  • @Override 注解用来表明该方法是重写父类方法,编译器会负责检查该方法与父类方法的声明是否一致。
  • @Deprecated 注解用来表明该元素已经被废弃不建议使用了。
  • @SuppressWarnings 注解用来表示编译器可以忽略特定警告。
@Retention

注解的保留位置:

  1. RetentionPolicy.SOURCE:源码阅读时使用,注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃。
  2. RetentionPolicy.CLASS:编译时使用,注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期。
  3. RetentionPolicy.RUNTIME:运行时使用,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。

这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码

@Target

注解作用目标:

  1. ElementType.TYPE:类、接口、枚举
  2. ElementType.FIELD:属性
  3. ElementType.METHOD:类中的方法
  4. ElementType.PARAMETER:方法参数
  5. ElementType.CONSTRUCTOR:构造器
  6. ElementType.LOCAL_VARIABLE:局部变量
  7. ElementType.ANNOTATION_TYPE:注解
  8. ElementType.PACKAGE:包

Java自定义注解

自定义注解:

/**
 * 定义类注解
 */
@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

Android中注解替代枚举/常量

通常定义固定值可以直接使用枚举或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);

你可能感兴趣的:(Android)