(2019.12.06)Java注解简单实践教程

(转载公司内部论坛本人文章2019.12.06)
Java的注解之前使用注解比较少,特此去了解了一下,并用注解对JsBridge代码重构了一下。重构后跳转Activity传参的方式如下:
改造前:
在这里插入图片描述
改造后:
在这里插入图片描述
其中 @JsParameter(“xxx”) 里面参数和json的key对应,然后BaseActivity里做了给加注解的成员变量自动赋值逻辑。可以看到,加了注解后,逻辑更加清晰了。之前那种方式,如果开发一不留意改了变量的命名,就会造成JsBridge跳转失败,加了注解后,可以规避这个问题。
BaseActivity关键代码和注解实现如下:

  private void setJsField() {
        if (getJsJSONObject() == null) {
            return;
        }
        Field[] fields = getClass().getDeclaredFields();
        Set<Map.Entry<String, Object>> entrySet = getJsJSONObject().entrySet();
        int noSetFieldSize = entrySet.size();
        for (Field field : fields) {
            if (field.isAnnotationPresent(JsParameter.class)) {
                JsParameter jsParameter = field.getAnnotation(JsParameter.class);
                setFor : for (Map.Entry<String, Object> entry : entrySet) {
                    if (TextUtils.equals(entry.getKey(), jsParameter.value())) {
                        try {
                            field.setAccessible(true);
                            field.set(this, entry.getValue());
                            noSetFieldSize--;
                            break setFor;
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            if (noSetFieldSize <= 0) {
                break;
            }
        }
    }

/**
 * 注解实现代码
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface JsParameter {

    String value() default "";
}

下面是对注解一些浅析,有兴趣的可以继续往下看。

什么是注解?

官方解释:
注解 (Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
个人理解:
所谓的注解其实就是给类,变量,方法等加注释,让一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。如给一个类或方法加@Deprecated,则可以告诉编译器该类或方法属于已过期。

注解定义

注解通过 @interface 关键字进行定义。

public @interface JsParameter {
}

注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。在注解中定义属性时它的类型必须是 8 种基本数据类型外加类、接口、注解及它们的数组。

public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Hi";
}

上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性,默认值分别是-1,“Hi”。在使用的时候,我们应该给它们进行赋值。赋值的方式是在注解的括号内以value="" 形式,多个属性之前用,隔开。不赋值则取默认值。

@TestAnnotation(id=3,msg="hello annotation")
public class Test {

}

另外,如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。也就是我上面那个例子,可以直接注解 @JsParameter(“id”)

public @interface JsParameter {
    String value() default "";
}

@JsParameter("id")
private String mMerchantId;

什么是元注解?

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

@Retention

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的存活时间。
它的取值如下:
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
如我上面的例子,注解可以保留到运行时中,这样才能在运行时中获取到value值:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface JsParameter {

    String value() default
}
@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Target

Target 是目标的意思,@Target 指定了注解运用的地方,可以理解为该注解能注解什么。
比如 @Target(ElementType.FIELD) 表示该注解只能注解成员变量。
其他还有 ElementType.METHOD,ElementType.TYPE,ElementType.CONSTRUCTOR 等类型

@Inherited

Inherited 是继承的意思,一个超类@Inherited的注解注解了,那么该超类的子类会默认拥有该注解,有点绕,可以下下面例子

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}

@Test
public class A {}

public class B extends A {}

注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个。举个例子

@interface Persons {
    Person[]  value();
}

@Repeatable(Persons.class)
@interface Person{
    String role default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{

}

注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。
我们再看看代码中的相关容器注解。

@interface Persons {
    Person[]  value();
}

按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。我们可能对于 @Person(role=”PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM 。

注解的提取

一般我们在定义和使用注解后,还需要提取注解,也就是怎么能在代码中利用到注解的值。
其实还是要利用到反射。
注解通过反射获取。在Class 对象中有如下方法操作注解Annotation的:
isAnnotationPresent() 方法判断它是否应用了某个注解
getAnnotation(Class annotationClass) 方法来获取 Annotation 对象。
getAnnotations() 方法返回注解到这个元素上的所有注解。
然后利用Annotation对象获得属性值。
如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如我重构的例子。

    @JsParameter("id")
    private String mMerchantId;
    @JsParameter("tab")
    private int mTab;

private void setJsField() {
        if (getJsJSONObject() == null) {
            return;
        }
        Field[] fields = getClass().getDeclaredFields();
        Set<Map.Entry<String, Object>> entrySet = getJsJSONObject().entrySet();
        int noSetFieldSize = entrySet.size();
        for (Field field : fields) {
            if (field.isAnnotationPresent(JsParameter.class)) {
                JsParameter jsParameter = field.getAnnotation(JsParameter.class);
                setFor : for (Map.Entry<String, Object> entry : entrySet) {
                    if (TextUtils.equals(entry.getKey(), jsParameter.value())) {
                        try {
                            field.setAccessible(true);
                            field.set(this, entry.getValue());
                            noSetFieldSize--;
                            break setFor;
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            if (noSetFieldSize <= 0) {
                break;
            }
        }
    }

其中 jsParameter.value() 的值分别是id和tab。

以上是本人对注解的一些浅析,如有写得不对的地方,欢迎指出。
参考资料:
https://www.jianshu.com/p/420d0f73809e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值