美文网首页
Java注解

Java注解

作者: 欢欢喜喜AA | 来源:发表于2017-07-28 10:14 被阅读0次

    元数据

    元数据是指用来描述数据的数据(“data about data”),简单的说,就是描述代码间关系,代码本身,资源数据等的数据。一般是结构化数据(如存储在数据库里的数据,规定了字段的长度、类型等)。元数据是指从信息资源中抽取出来的用于说明其特征、内容的结构化的数据。
    比如,关于一本书(信息资源),我们在图书馆系统中检索可以得到题名,版本、出版数据、相关说明,包括检索点等,这些就是元数据,用于描述资源的。

    Java注解

    JDK5.0引入了Annotation的概念来描述元数据,在java中,元数据是以标签的形式存在,元数据并不会影响程序代码的编译和执行。JDK5.0出来后,java语言中有四种类型,class(类)、enum(枚举)、interface(接口)和@interface(注解),他们在java中处于同一级别。元数据在java中,既是由注解来表示的。注解可以在编译、类加载和运行时被读取。
    Java的注解本质上是一个接口,继承了接口Annotation的接口,这里的继承用的是extends。

    注解既然和接口类似,就会包含成员:

    • final静态属性,必须初始化
    • 公共抽象方法,可设置默认值

    @interface隐含继承Annotation,但是自定义注解不能直接继承Annotation。直接继承的是接口,非注解。

    注解的作用

    1. 编写文档(通过代码里面标识的元数据编写,例如@param,@return)
    2. 代码分析(可以替代配置文件)
    3. 编译检查(通常配合lint使用,如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。)

    Java中自带的注解

    (基本)

    1. @Override(限定重写父类的方法)
    2. @SuppressWarning(用于抑制编译器产生警告信息)
    3. @Deprecated(表示"已过时/不建议使用/在后期的API中可能被删除")
    4. @SafeVarargs(java7新增,和堆污染有关,具体不是很了解)
      (用于标识注解的注解)
    5. @Retention(决定注解存活和读取时间,它包含一个RetationPolicy的value成员变量,用于指定它所修饰的注解的读取和存活时间)
      一般的值有:
      • Retationpolicy.CLASS:在类加载的时候解读,执行的时候,jvm就会抛弃掉。
      • Retationpolicy.ROURCE:存在于源码中,在编译的时候解读,之后就抛弃,不进入类加载和运行环节。
      • Retationnpolicy.RUNTIME:运行时解读,可以在运行时通过反射获取注解,执行操作。
    6. @Target (指定修饰的元素,包含一个value值)
      value可选:
      • ElementType.ANNOTATION_TYPE: 指定该Annotation只能修饰Annotation。
      • ElementType.CONSTRUCTOR: 指定只能修饰构造器。
      • ElementType.FIELD: 指定只能成员变量。
      • ElementType.LOCAL_VARIABLE: 指定只能修饰局部变量。
      • ElementType.METHOD: 指定只能修饰方法。
      • ElementType.PACKAGE: 指定只能修饰包定义。
      • ElementType.PARAMETER: 指定只能修饰参数。
      • ElementType.TYPE: 指定可以修饰类,接口,枚举定义。
    7. @Document(可被javadoc提取成文档)
    8. @Inherited 被他修饰的Annotation具有继承性

    自定义注解

    最简单的例子,Android中代替findviewById()对组件进行初始化。只需要在成员变量组件前加上注解就行,能有效的减少代码量,可读性更强。

    首先定义注解,运行时读取,作用于成员变量
    写法和接口雷同
    用法是@FindView(R.id.XXX)这里传入的Id就是这个value的返回值,可以在获取到这个注解实例后调用这个value() 方法获取值
    可以不止一个方法,多一个方法,就可以多传一个参数,如果有默认值,也可以不传

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface FindView{
        /**
         * id 注解,这里没有默认值,不过可以自由添加,
         * 例如:public String tableName() default "className";
         * @return
         */
        int value();
    }
    

    从上面注解的定义来,类似于接口,所以注解本身不具备解析和其他操作的功能,这里我们想要的是利用这个注解携带的value,初始化这个注解所表示的成员变量,所以我们需要自己写一个工具类,通过传入的activity获取注解,并利用反射初始化成员变量。以下是详细代码:

    public class ViewUtil {
        public static void viewInject(Activity activity){
            viewInjects(activity);
        }
    
        private static void viewInjects(Activity activity){
            Class<? extends Activity> clazz = activity.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for(Field field:fields){
                FindView viewFind = field.getAnnotation(FindView.class);
                if(viewFind!=null){
                    int viewId = viewFind.value();
                    View view = activity.findViewById(viewId);
                    try {
                        field.setAccessible(true);
                        field.set(activity, view);
    
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    最后是具体的使用方法

    public class MainActivity extends AppCompatActivity {
           @FindView(R.id.btn)
        Button btn;
        @FindView(R.id.btn1)
        Button btn1;
        @FindView(R.id.btn2)
        Button btn2;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ViewUtil.viewInject(this);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    btn.setText("Test2");
                }
            });
        }
    }
    

    以上是@Retention(RetentionPolicy.RUNTIME)运行时解读的具体写法。
    优点是可读性强,写起来简单。
    缺点便是常驻内存,并利用反射进行初始化,耗费内存

    如何解决这个问题呢?其实我们可以利用apt,使用编译时解读或者类加载时解读,后面的文章我会重点讲到,这里就不多啰嗦了。

    So easy!

    相关文章

      网友评论

          本文标题:Java注解

          本文链接:https://www.haomeiwen.com/subject/bxznkxtx.html