关于java注解

来源:互联网 发布:自学入门java看什么书 编辑:程序博客网 时间:2024/05/09 15:19

刚进公司的时候,clone了花果山的代码下来看,很幸运,这个项目刚刚开始,我可以把leo的框架先完整的看一遍而不受其他细节的影响,Leo写了非常多的基础类,非常多的抽象类,整个app的网络请求,加载图片,ListView加载数据都已经封装好,在这个基础上,我们的代码一下简化了不少,但另一方面,我们需要去理解Leo写的这些类到底为我们做了什么,当我开始找所有的基类的时候,我发现有些类根本在project里找不到,甚至连第三方类库也找不到,后来在Leo帮忙配置环境的时候我才知道,原来这些类都在远程库里,需要gradle去下载相应的依赖(之前都是用的Eclipse开发,Android studio最近才用,所以gradle我并不熟悉),这次就不谈gradle了,因为让我觉得神奇的代码其实是Leo写的注解,java算是白学了,每次看书看到注解的时候都以为只是简单的注释没必要看,直到看到Leo用@ViewById代替findViewById方法让代码看上去简洁清晰的时候我知道我该看看Java的注解了:

java为我们提供了元注解,元注解负责注解其他注解:@Target,@Retention,@Documented,@Inherited,根据这四个我们可以自定义自己的注解

我们只讨论前两个,因为前两个比较常用,也是Leo使用的

1.@Target说明了自定义注解修饰的对象,取值(ElementType)可以是

1.CONSTRUCTOR:用于描述构造器

2.FIELD:用于描述域

3.LOCAL_VARIABLE:用于描述局部变量

4.METHOD:用于描述方法

5.PACKAGE:用于描述包

6.PARAMETER:用于描述参数

7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

2.@Retention说明了自定义注解保留的时间,取值(RetentionPoicy)可以是

1.SOURCE:在源文件中有效(即源文件保留)

2.CLASS:在class文件中有效(即class保留)

3.RUNTIME:在运行时有效(即运行时保留)

知道这两个后,我们可以自定义注解了,自定义注解一共三步:一是定义注解,二是定义注解处理器,三是使用注解。

一.定义注解

为了和接口区分,Java在interface关键字前加一个@符号来定义注解

@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface ViewById {    int value() default -1;    int id() default -1;}

可以看到Leo自定义ViewById注解修饰的对象是域,并且是在运行是有效,value表示域的值


二.定义注解处理器

    public static int inject(Object object, View view) {        int injectCount = 0;        Field[] fields = object.getClass().getDeclaredFields();        Field[] arr$ = fields;        int len$ = fields.length;        for(int i$ = 0; i$ < len$; ++i$) {            Field field = arr$[i$];            field.setAccessible(true);            try {                if(field.get(object) == null) {                    ViewById e = (ViewById)field.getAnnotation(ViewById.class);                    if(e != null) {                        int viewId = e.value() != -1?e.value():e.id();                        if(viewId != -1) {                            field.set(object, view.findViewById(viewId));                            ++injectCount;                        }                    }                }            } catch (IllegalAccessException var10) {                var10.printStackTrace();            } catch (IllegalArgumentException var11) {                Log.e(TAG, "Field name : " + field.getName());                var11.printStackTrace();            }        }        return injectCount;    }

可以看到,Leo先把对象里所有的域找出来放到一个数组,然后对数组的每一个域通过java的反射机制得到访问权限,用

ViewById e = (ViewById)field.getAnnotation(ViewById.class);
获取到该域的注解,然后用

field.set(object, view.findViewById(viewId));
为该域调用findViewById方法

三.使用注解

在BaseActivity中调用:

inject(activity, activity.getWindow().getDecorView());

之后所有继承BaseActivity的Activity中都可以直接使用

    @ViewById(R.id.name)    private EditText mName;

这两行就代替了以下代码:

private EditText mName;mName = findViewById(R.id.name);
而且关键是可以在Activity的域中使用,而不用在onCreate()方法中去调用findViewById方法。使代码看上去简洁清晰了许多。


0 0
原创粉丝点击