Java_注解 (元注解 / Java内置注解 / Android内置注解)

19 篇文章 0 订阅

Java_注解 (元注解 / Java内置注解 / Android内置注解)


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/rozol/article/details/77758192


注解: 给程序看的提示. (注释: 给程序员看的提示)
Java1.5开始引入注解功能.
元数据: 描述数据的数据, 可以说注解便是这元数据. (除注解外, XML也被用于描述元数据)
注解仅仅是元数据, 与业务逻辑无关, 注解的 添加 / 删除 不能影响程序的执行

元注解

元注解

  • @Retention(RetentionPolicy.RUNTIME) // @Retention指定注解的(生命周期)保留范围(默认CLASS) (SOURCE:在编译阶段丢弃 / CLASS:在类加载时丢弃(在字节码文件中有用) / RUNTIME:始终存在(可反射读取))
  • @Target({ElementType.TYPE, ElementType.METHOD}) // @Target:指定注解被用于什么地方(默认用于任何地方) (TYPE: 类,接口,enum / FIELD: 字段 / METHOD: 方法 / PARAMETER: 参数 / CONSTRUCTOR: 构造 / LOCAL_VARIABLE: 局部变量 / ANNOTATION_TYPE: 注解 / PACKAGE: 包 / TYPE_PARAMETER: 类型参数 / TYPE_USE: 类型使用)
  • @Documented // 将被 javadoc 工具提取成文档
  • @Inherited // 被该注解修饰的类(在类上声明才有效)具有继承性 (父类使用@Inherited修饰类, 其子类自动具有该注解)
  • @Repeatable(ArrayAnnotation.class) // 可重复的注解 (使用该注解还需创建 @ArrayAnnotation 注解) (使用: @JavaAnnotations())
/**
 * Java的元注解
 * Java1.8的 @Target 注解引入了 TYPE_PARAMETER 和 TYPE_USE
 * Java1.8引入了 @Repeatable 注解
 * @author Luzhuo
 */
@Retention(RetentionPolicy.RUNTIME) // @Retention指定注解的(生命周期)保留范围(默认CLASS) (SOURCE:在编译阶段丢弃 / CLASS:在类加载时丢弃(在字节码文件中有用) / RUNTIME:始终存在(可反射读取))

@Target({ElementType.TYPE, ElementType.METHOD}) // @Target:指定注解被用于什么地方(默认用于任何地方) (TYPE: 类,接口,enum / FIELD: 字段 / METHOD: 方法 / PARAMETER: 参数 / CONSTRUCTOR: 构造 / LOCAL_VARIABLE: 局部变量 / ANNOTATION_TYPE: 注解 / PACKAGE: 包 / TYPE_PARAMETER: 类型参数 / TYPE_USE: 类型使用)

@Documented // 将被 javadoc 工具提取成文档

@Inherited // 被该注解修饰的类(在类上声明才有效)具有继承性 (父类使用@Inherited修饰类, 其子类自动具有该注解)

@Repeatable(ArrayAnnotation.class) // 可重复的注解 (使用该注解还需创建 @ArrayAnnotation 注解) (使用: @JavaAnnotations())
public @interface MetaAnnotations { // @interface关键字来定义注解

    // 只有的数据类型有: 基本数据类型 / String / Class / enum / Annotation / <- 这些数据类型对应的一位数组
    public String name() default "JavaAnnotations"; // default 设置默认值 (没写默认值,使用时编译器会要求加上该属性) (默认值不能为null, 可用 -1 或 "" 表示该元素不存在)

    public int number() default 100;

    public String value() default ""; // 当注解只包含一个名为 value 的属性时, 该注解在被使用时可忽略属性名直接写值

    public enum Color{RED, YELLOW, BULE};
    public Color color() default Color.BULE;
}



/**
 * 当 MetaAnnotations 注解使用了 @Repeatable 可重复注解后, 还需创建一个 ArrayAnnotation 注解, 用于存放 MetaAnnotations 注解.
 * ArrayAnnotation 使用的元注解必须和 MetaAnnotations 一样
 * @author Luzhuo
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Inherited
@interface ArrayAnnotation {
    public MetaAnnotations[] value();
}

注解及其属性获取

注解 通过反射获取的类 / 方法 / 字段 上获取

public class Test {
    public static void main(String[] args) throws Exception {

        Class<?> clazz = Bean.class;

        // 获取类的注解
        classAnnotations(clazz);

        // 获取方法的注解
        methodAnnotations(clazz);
    }



    /**
     * 获取类的注解
     */
    private static void classAnnotations(Class<?> clazz) {
        Annotation[] annotations = clazz.getAnnotations(); // 获取所有注解(含父类)
        Annotation[] allAnnotations = clazz.getDeclaredAnnotations(); // 返回本类的所有注解(不含父类)

        MetaAnnotations metaAnnotations = clazz.getAnnotation(MetaAnnotations.class); // 获取指定的注解, 不存在null
        boolean exist = clazz.isAnnotationPresent(MetaAnnotations.class); // 是否存在该注解


        System.out.println("Class annotations[]: " + Arrays.toString(annotations));
        System.out.println("Class allAnnotations[]: " + Arrays.toString(allAnnotations));
        System.out.println("Class metaAnnotations: " + metaAnnotations);
        System.out.println("Class exist: " + exist);
    }

    /**
     * 获取方法的注解
     */
    private static void methodAnnotations(Class<?> clazz) throws Exception {
        Method method = clazz.getMethod("show");

        Annotation[] annotations = method.getAnnotations();
        Annotation[] allAnnotations = method.getDeclaredAnnotations();

        // 注意: 当拥有多条相同的注释时, 使用的是 ArrayAnnotation 而非 MetaAnnotations .
        ArrayAnnotation arrayAnnotation = method.getAnnotation(ArrayAnnotation.class);
        boolean exist = method.isAnnotationPresent(ArrayAnnotation.class);

        // Java8新增的方法
        MetaAnnotations[] annotations_new = method.getAnnotationsByType(MetaAnnotations.class);
        MetaAnnotations[] allAnnotations_new = method.getDeclaredAnnotationsByType(MetaAnnotations.class);


        System.out.println("Method annotations[]: " + Arrays.toString(annotations));
        System.out.println("Method allAnnotations[]: " + Arrays.toString(allAnnotations));
        System.out.println("Method arrayAnnotation: " + arrayAnnotation);
        System.out.println("Method exist: " + exist);

        System.out.println("Method new annotations[]: " + Arrays.toString(annotations_new));
        System.out.println("Method new allAnnotations[]: " + Arrays.toString(allAnnotations_new));
    }
}

/**
 * 使用注解
 * @author Luzhuo
 */
@MetaAnnotations(name = "Test", value = "abc")
class Bean {
    @MetaAnnotations(color = Color.RED)
    @MetaAnnotations(number = 10)
    public void show(){}
}

Java8新注解详解

@Target 注解引入了 TYPE_PARAMETER 和 TYPE_USE
@Repeatable 注解

/**
 * Java1.8新增的注解专讲
 * Java1.8的 @Target 注解引入了 TYPE_PARAMETER 和 TYPE_USE
 * Java1.8引入了 @Repeatable 注解
 * @author Luzhuo
 */
public class Java8NewAnnotations {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = new Bean2<Integer>().getClass();

        // @Target 注解的 ElementType.TYPE_PARAMETER
        // Bean<T> 泛型 #TODO



        // =================================================



        // @Target 注解的 ElementType.TYPE_USE
        // === 类 ===
        Targe_TYPE_USE classTypeUse = clazz.getAnnotation(Targe_TYPE_USE.class);
        System.out.println("classTypeUse: " + classTypeUse);

        // === 接口 ===
        AnnotatedType[] annoInterfaces = clazz.getAnnotatedInterfaces(); // 获取注解接口 Java1.8
        for (AnnotatedType annoType : annoInterfaces){
            Type type = annoType.getType();
            Annotation[] interfaceAnnotations = annoType.getAnnotations();
            System.out.println("接口类型: " + type.toString() + " 接口的注解: " + Arrays.toString(interfaceAnnotations));
        }



        // === 字段 ===
        Field[] fields = clazz.getFields();

        // list 泛型 #TODO
        Field list = fields[0];


        // name
        Field name = fields[1];

        // 1. 字段类型
        Type nameType = name.getType();
        AnnotatedType stringType = name.getAnnotatedType(); // 获取 name 注解类型 String Java1.8
        Annotation[] stringAnnotations = stringType.getAnnotations(); // 获取 String 的注解
        System.out.println("name字段类型: " + nameType.toString() + " 字段的注解: " + Arrays.toString(stringAnnotations));

        // 2. 类型强转 #TODO



        // file #TODO
        Field file = fields[2];


        // === 方法 ===
        Method getName = clazz.getMethod("getName", String.class);

        // 返回
        AnnotatedType returnType = getName.getAnnotatedReturnType(); // Java1.8
        Annotation[] returnAnnotaions = returnType.getAnnotations();
        System.out.println("返回类型: " + returnType.getType().toString() + " 返回注解: " + Arrays.toString(returnAnnotaions));

        // 参数
        AnnotatedType[] parameters = getName.getAnnotatedParameterTypes();
        for (AnnotatedType parameter : parameters){
            Type type = parameter.getType();
            Annotation[] parameterAnnotations = parameter.getAnnotations();
            System.out.println("参数类型: " + type.toString() + " 参数注解: " + Arrays.toString(parameterAnnotations));
        }

        // 异常
        AnnotatedType[] exceptions = getName.getAnnotatedExceptionTypes();
        for (AnnotatedType excep : exceptions){
            Type type = excep.getType();
            Annotation[] exceptionAnnotations = excep.getAnnotations();
            System.out.println("异常类型: " + type.toString() + " 异常注解: " + Arrays.toString(exceptionAnnotations));
        }



        // =================================================



        // @Repeatable √
        Annotation[] annotations_repeatable = clazz.getAnnotationsByType(Targe_Repeatable.class);
        System.out.println("@Repeatable: " + Arrays.toString(annotations_repeatable));
    }
}

// === 使用注解 ==================================
// @Repeatable
@Targe_Repeatable("abc√")
@Targe_Repeatable("123√")

@Targe_TYPE_USE("类√")

// @Target - TYPE_PARAMETER
class Bean2<@Targe_TYPE_PARAMETER("泛型") T> implements @Targe_TYPE_USE("接口√") Serializable{

    // @Targe - TYPE_USE
    public List<@Targe_TYPE_USE("泛型") String> list = new ArrayList<>();
    public @Targe_TYPE_USE("字段类型√") String name = (@Targe_TYPE_USE("类型强转") String) "Bean";
    public File file = new java.io.@Targe_TYPE_USE("创建对象") File("filename");

    public @Targe_TYPE_USE("返回√") String getName(@Targe_TYPE_USE("参数√") String name) throws @Targe_TYPE_USE("抛异常√") Exception{
        return name;
    }
}


// === 定义注解 ==================================

/**
 * @Target 注解的 ElementType.TYPE_PARAMETER
 * 类型参数: 用来标注 类型参数<T>.
 * @author Luzhuo
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_PARAMETER)
@interface Targe_TYPE_PARAMETER {
    public String value() default "TYPE_PARAMETER";
}

/**
 * @Target 注解的 ElementType.TYPE_USE
 * 类型使用: 只要是 类型 ,都可以进行注解.
 * @author Luzhuo
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface Targe_TYPE_USE {
    public String value() default "TYPE_USE";
}

/**
 * @Repeatable 注解
 * 可重复的注解
 * @author Luzhuo
 */
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ArrayRepeatable.class)
@interface Targe_Repeatable {
    public String value() default "Repeatable";
}

@Retention(RetentionPolicy.RUNTIME)
@interface ArrayRepeatable {
    public Targe_Repeatable[] value();
}

Java内置注解

Override(复写父类方法) / Deprecated(不建议使用) / SuppressWarnnings(抑制编译器警告)

/**
 * Java内置的注解
 * Override(复写父类方法) / Deprecated(不建议使用) / SuppressWarnnings(抑制编译器警告) 
 * @author Luzhuo
 */
public class JavaAnnotations extends Annotation {
    /**
     * 告知编译器忽略指定警告信息
     */
    @SuppressWarnings("rawtypes")
    public List list = new ArrayList();

    public JavaAnnotations(Object value) {
        super(value);
    }

    /**
     * 复写父类的方法
     */
    @Override
    public Object getValue() {
        return super.getValue();
    }

    /**
     * 告知编译器不建议使用
     */
    @Deprecated
    public String getName() {
        return JavaAnnotations.class.getSimpleName();
    }

    /**
     * 告知编译器, 程序员写的正文代码不会对其 可变参数 执行潜在的不安全操作
     * Type safety: Potential heap pollution via varargs parameter list. (潜在的可变参数列表堆污染)
     * Java 1.7
     */
    @SafeVarargs
    public static void aaa(List<String>... list){
        // 把类型弄乱套, 编译器并不会报错
        Object[] array = list; // 参数被重新构建元素类型, 他的类型包括 Object / String.
        array[0] = 123;
    }

    /**
     * 函数式接口, 主要用于Lambda表达式
     * 只有一个抽象方法的普通接口 (多个 default / static 方法不受影响)
     * @author Luzhuo
     */
    @FunctionalInterface
    public interface RunnableTest {
        // 只能有一个抽象方法
        public abstract void runTest(String id);

        // 其他的, 多个不影响
        public default String getName(){ 
            return RunnableTest.class.getSimpleName();
        }
        public static int getId(){
            return 0x007;
        }
    }

    public static void main(String[] args) {
        // Lambda表达式
        RunnableTest runnable = id -> System.out.println("RunnableTest: " + id);
        runnable.runTest("123");

        // 其他方法的使用
        System.out.println("Name: " + runnable.getName());
        System.out.println("Id: " + RunnableTest.getId());
    }
}

Android内置注解

  • Nullness, 参数 或 返回值 为 null 或 非null
  • 资源类注解: @StringRes (R.string.xxx), @DrawableRes (R.mipmap.xxx), @ColorRes (R.color.xxx),@LayoutRes(R.layout.xxx), @AnyRes(任意资源), @AnimatorRes, @AnimRes, @FranctionRes, @InterpolatorRes, @XmlRes, @ArrayRes, @AttrRes, @BoolRes, @IntegerRes, StringRes, @IdRes, @RawRes, @MenuRes, @StyleableRes @StyleRes
  • 线程相关注解: @UiThread, @MainThread, @WorkerThread, @BinderThread
  • 参数类型 及其 范围 相关注解: @Size(数组 / 集合 / 字符串 的大小) / @IntRange / @FloatRange
  • 权限注解: @RequiresPermission
  • @CheckResult 建议对返回值做些操作
  • @CallSuper 方法重写后要调用父类方法

Nullness

Nullness, 参数 或 返回值 为 null 或 非null

注解使用

/**
 * Nullness, 参数 或 返回值 为 null 或 非null
 */
public class NullnessAnnotations {

    /**
     * 参数不能为null
     */
    public void print1(@NonNull String id){
        System.out.println(id);
    }

    /**
     * 参数可以为null
     */
    public void print2(@Nullable Integer id){
        System.out.println(id);
    }

    /**
     * 返回值不能为null
     */
    @NonNull
    public String getName1(){
        return null; // 'null' is returned by the method declared as @NotNull
    }

    /**
     * 返回值可以为null
     */
    @Nullable
    public String getName2(){
        return null;
    }
}

测试

// Nullness 是否为空注解
NullnessAnnotations nullnessTest = new NullnessAnnotations();
nullnessTest.print1(null); // Passing 'null' argument to parameter annotated as @NotNull
nullnessTest.print2(null);

nullnessTest.getName1();
nullnessTest.getName2();

资源类型注解, 限制参数的资源类型

@StringRes (R.string.xxx), @DrawableRes (R.mipmap.xxx), @ColorRes (R.color.xxx), @LayoutRes(R.layout.xxx), @AnyRes(任意资源)
@AnimatorRes, @AnimRes, @FranctionRes, @InterpolatorRes, @XmlRes
@ArrayRes, @AttrRes, @BoolRes, @IntegerRes, StringRes, @IdRes, @RawRes
@MenuRes, @StyleableRes @StyleRes

注解使用

/**
 * 资源类型注解, 限制参数的资源类型
 * @StringRes (R.string.xxx), @DrawableRes (R.mipmap.xxx), @ColorRes (R.color.xxx), @LayoutRes(R.layout.xxx), @AnyRes(任意资源)
 * @AnimatorRes, @AnimRes, @FranctionRes, @InterpolatorRes, @XmlRes
 * @ArrayRes, @AttrRes, @BoolRes, @IntegerRes, StringRes, @IdRes, @RawRes
 * @MenuRes, @StyleableRes @StyleRes
 */
public class ResTypeAnnotations {
    /**
     * String类型 资源
     */
    public void setStringRes(@StringRes int id){
        System.out.println(id);
    }

    /**
     * Drawable类型 资源
     */
    public void setImageRes(@DrawableRes int id){
        System.out.println(id);
    }

    /**
     * Color类型 资源
     */
    public void setColorRes(@ColorRes int id){
        System.out.println(id);
    }

    /**
     * Interpolator类型(xml插值器文件) 资源
     */
    public void setInterPolatorRes(@InterpolatorRes int id){
        System.out.println(id);
    }

    // ...

    /**
     * 任何资源
     */
    public void setAnyRes(@AnyRes int id){
        System.out.println(id);
    }
}

测试

// Res 资源类型注解
ResTypeAnnotations resIdTest = new ResTypeAnnotations();
resIdTest.setStringRes(123456); // Expected resource of type string
resIdTest.setStringRes(R.color.colorAccent); // Expected resource of type string
resIdTest.setStringRes(R.string.app_name);

resIdTest.setImageRes(R.mipmap.ic_launcher);

resIdTest.setColorRes(R.color.colorAccent);

resIdTest.setAnyRes(123456);
resIdTest.setAnyRes(R.color.colorAccent);

线程相关注解

线程相关注解: @UiThread, @MainThread, @WorkerThread, @BinderThread

注解使用

/**
 * 线程相关注解
 * @UiThread, @MainThread, @WorkerThread, @BinderThread
 */
public class ThreadAnnotaions {
    /**
     * UI线程, 标记该方法运行于UI线程, 也就是Activity运行的窗口
     * 一个应用可能有多个UI线程
     */
    @UiThread
    public void runUI(){
        System.out.println("UiThread");
    }

    /**
     * 主线程, 标记该方法运行于主线程
     * 主线程也是UI线程, 于UiThread差别不大, 一般用UiThread标记
     */
    @MainThread
    public void runMain(){
        System.out.println("MainThread");
    }

    /**
     * 辅助线程, 标记该方法运行于子线程
     */
    @WorkerThread
    public void runWorker(){
        System.out.println("WorkerThread");
    }

    /**
     * Binder线程, 标记该方法运行于Binder线程池
     */
    @BinderThread
    public void runBinder(){
        System.out.println("BinderPoolThread");
    }
}

测试

// 线程相关注解
final ThreadAnnotaions threadAnnotaions = new ThreadAnnotaions();
threadAnnotaions.runUI();
threadAnnotaions.runMain();
threadAnnotaions.runWorker(); // Method runWorker must be called from the worker thread, currently inferred thread is main
threadAnnotaions.runBinder(); // Method runBinder must be called from the binder thread, currently inferred thread is main

new Thread(new Runnable() {
    @Override
    public void run() {
        // 子线程
        threadAnnotaions.runUI(); // TODO UIThread未被编译器警告提示
        threadAnnotaions.runMain(); // TODO MainThread未被编译器警告提示
        threadAnnotaions.runWorker();
        threadAnnotaions.runBinder();
    }
}).start();

参数类型 及其 范围 相关注解

@Size(数组 / 集合 / 字符串 的大小) / @IntRange / @FloatRange

注解使用

/**
 * 参数类型 及其 范围 相关注解
 * 当方法传入的参数值在一定的范围时, 可防止用户传入非期望的值
 * @Size(数组 / 集合 / 字符串 的大小) / @IntRange / @FloatRange
 */
public class RangeAnnotations {

    // @Size(数组 / 集合 / 字符串 的大小)

    /**
     * 数组 / 集合 / 字符串 的大小最小为3
     */
    public void setArrayMin(@Size(min = 3) int[] ints){
        System.out.println(Arrays.toString(ints));
    }

    /**
     * 大小最大为5
     */
    public void setArrayMax(@Size(max = 5) int[] ints){
        System.out.println(Arrays.toString(ints));
    }

    /**
     * 大小限制为2
     */
    public void setArray(@Size(2) int[] ints){
        System.out.println(Arrays.toString(ints));
    }

    /**
     * 大小限制为2的倍数
     */
    public void setArrayMul(@Size(multiple=2) int[] ints){
        System.out.println(Arrays.toString(ints));
    }



    // @IntRange / @FloatRange 限制数字类型, 及其范围

    /**
     * 限制参数为整数类型 (参数可为: int long)
     * 并且可限制其范围
     */
    public void setInt(@IntRange(from = 1, to = 3) int number){
        System.out.println(number);
    }

    /**
     * 限制参数类型为浮点数类型 (参数可为: float double)
     * 并且可限制其范围
     */
    public void setFloat(@FloatRange(from = 0.0, to = 1.0) float number){
        System.out.println(number);
    }
}

测试

// 参数值范围相关注解
RangeAnnotations rangeAnnotations = new RangeAnnotations();
rangeAnnotations.setArrayMin(new int[]{1}); // Size must be at least 3 (was 1)
rangeAnnotations.setArrayMin(new int[]{1, 2, 3});

rangeAnnotations.setArrayMax(new int[]{1, 2, 3, 4, 5});
rangeAnnotations.setArray(new int[]{1, 2});
rangeAnnotations.setArrayMul(new int[]{1, 2});


// @IntRange / @FloatRange 限制数字类型, 及其范围
rangeAnnotations.setInt(1);
rangeAnnotations.setFloat(0.1f);

权限注解

@RequiresPermission 权限注解

注解使用

/**
 * @RequiresPermission 权限注解
 */
public class PermissionAnnotations {
    /**
     * 字段的单个权限, 直接写在常量字段上
     */
    @RequiresPermission(android.Manifest.permission.BLUETOOTH)
    public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

    /**
     * 字段的读写个权限
     */
    @RequiresPermission.Read(@RequiresPermission("me.luzhuo.permission.READ_PROVIDER"))
    @RequiresPermission.Write(@RequiresPermission("me.luzhuo.permission.WRITE_PROVIDER"))
    public static final Uri PersonUri = Uri.parse("content://me.luzhuo.person_provider/person");

    /**
     * 需要指定的注解
     */
    @RequiresPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
    public void readFile(){
        System.out.println("readFile");
    }

    /**
     * 至少需要权限集中的一个
     */
    @RequiresPermission(anyOf = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public void writeFile(){
        System.out.println("writeFile");
    }

    /**
     * 需要权限集里的全部权限
     */
    @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public void readAndWriteFile(){
        System.out.println("readAndWriteFile");
    }
}

测试

// @RequiresPermission
PermissionAnnotations permissionAnnotations = new PermissionAnnotations();
permissionAnnotations.readFile(); // Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    // 如果检查权限通过
    permissionAnnotations.writeFile();
}

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    permissionAnnotations.readAndWriteFile();
}

if (ContextCompat.checkSelfPermission(this, "me.luzhuo.permission.READ_PROVIDER") == PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this, "me.luzhuo.permission.WRITE_PROVIDER") == PackageManager.PERMISSION_GRANTED) {
    getContentResolver().delete(PermissionAnnotations.PersonUri, "`_id = ?", new String[]{"21"});
}

@CheckResult 建议对返回值做些操作

@CheckResult

注解使用

/**
 * @CheckResult 建议对返回值做些操作
 */
public class CheckResultAnnotations {

    /**
     * 对返回的结果, 建议调用 print(int) 操作
     */
    @CheckResult(suggest = "#print(int)")
    public CheckResultAnnotations getInstance(){
        return this;
    }

    public void print(int number){
        System.out.println(number);
    }
}

测试

// @CheckResult 建议对返回值做些操作
CheckResultAnnotations checkResultAnnotations = new CheckResultAnnotations();
checkResultAnnotations.getInstance(); // The result of 'getInstance' is not used; did you mean to call 'print(int)'?
checkResultAnnotations.getInstance().print(1);

CallSuper 方法重写后要调用父类方法

@CallSuper

注解使用

/**
 * CallSuper 方法重写后要调用父类方法
 * 当该方法被复写时, 期望在复写后也要 调用该方法
 */
public class CallSuperAnnotations {

    /**
     * 方法复写时, 期望子类复写该方法后也要被 调用
     */
    @CallSuper
    public void print(){
        System.out.println(CallSuperAnnotations.class.getSimpleName());
    }
}

测试

/**
 * 子类
 */
class ChildCallSuperAnnotations extends CallSuperAnnotations{
    @Override
    public void print() {
        // 若不写, 则提示: Overriding method should call super.print
        super.print();
    }
}

其他

@VisibleForTesting 可标注到类 方法 字段上, 是否对测试可见
@Keep 保持代码,拒绝混淆

注解使用

/**
 * 其他注解
 *
 * @VisibleForTesting 可标注到类 方法 字段上, 是否对测试可见
 * otherwise: PRIVATE(private)(默认) / PACKAGE_PRIVATE(default) / PROTECTED(protected) / NONE
 *
 * @Keep 保持代码,拒绝混淆
 * 该注解标注到 类 / 方法 上时, 不会被混淆
 */
public class OtherAnnotations {

    /**
     * @VisibleForTesting 可标注到类 方法 字段上, 是否对测试可见
     */
    @VisibleForTesting
    public static class VisibleForTestingAnnotations {

        @VisibleForTesting
        public int  number = 100;

        /**
         * private 方法 为什么修饰符是 public, 因为测试无法访问私有方法, 告知这个 public 权限是给测试可见的, 原先权限是 private
         * 这个注解加不加都一样, 没什么卵用, 反正就是告诉你权限这回事儿, 并不会对权限造成任何影响
         */
        @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
        public String getName(){
            return VisibleForTestingAnnotations.class.getSimpleName();
        }
    }

    /**
     * @Keep 保持代码,拒绝混淆
     */
    @Keep
    public static class KeepAnnotations{
        @Keep
        public String getName(){
            return KeepAnnotations.class.getSimpleName();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值