专栏首页Android先生Android-Annotation教你写自定义注解

Android-Annotation教你写自定义注解

作者:那个人

地址:https://juejin.im/post/5a14158df265da432c237bfc

声明:本文是那个人原创,已获其授权发布,未经原作者允许请勿转载

一 前言

我相信注解我们多多少少的都会接触到,常用的框架Butterknife、Retrofit、ARouter等等都用到了注解,我想大家都会去搜一下什么是注解了吧。这里呢就以一个Demo去了解一下自定义注解的使用。

二 知识准备

我们最常见的注解莫过于@Override了吧,那我们就去看一下这个注解的代码。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

好了就事论事我们先看下声明这个@interface乍一看还以为是interface呢不过这里多了个@那就是声明注解的关键字了,这只要记住就好了。大括号里面竟然没任何的定义,那就先放一放,我们来看一下其他的参数。

  • @Target() @Target说明了Annotation所修饰的对象范围,也就是我们这个注解是用在那个对象上面的:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。 作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)取值(ElementType)是来源于Java.lang.annotation.ElementType中的枚举类型元素:    (1).CONSTRUCTOR:用于描述构造器    (2).FIELD:用于描述域    (3).LOCAL_VARIABLE:用于描述局部变量    (4).METHOD:用于描述方法    (5).PACKAGE:用于描述包    (6).PARAMETER:用于描述参数    (7).TYPE:用于描述类、接口(包括注解类型) 或enum声明
  • @Retention() @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。 作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)取值(RetentionPoicy)来源于java.lang.annotation.RetentionPolicy的枚举类型值:    (1).SOURCE:在源文件中有效(即源文件保留)    (2).CLASS:在class文件中有效(即class保留)    (3).RUNTIME:在运行时有效(即运行时保留)
  • @Documented() @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
  • @Inherited() @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
这里呢大概的讲了一下定义在类上面的每个注解的意义和取值是什么,下面我们将进入我们的自定义注解中。

三 自定义注解

我们先来照葫芦画瓢,定义一个注解类

public @interface MyTag {

}

注解里面的定义也是有规定的:

  • 注解方法不能带有参数
    • 注解方法返回值类型限定为:基本类型、String、Enums、Annotation或者这些类型的数组。
  • 注解方法可以有默认值
  • 注解本身能够包含元注解,元注解被用来注解其他注解

我们就来试一下吧!

public @interface MyTag {
  //声明返回值类型,这里可没有大括号啊,可以设置默认返回值,然后就直接";"了啊。
    String name () default "" ;

    int size () default 0 ;

}

定义好了注解我们就来规定我们这个注解要用到哪里何时用吧!

@Target({ElementType.METHOD,ElementType.FIELD})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
    String name () default "" ;
    int size () default 0 ;
}

这里呢我们定义这个注解可以用在属性和方法上面,是可继承的注解,可以出现在运行时的。因为我们这边要模仿一下一下其他注解框架中注解的用法,我这里才采用了RetentionPolicy.RUNTIME,因为在运行时我们采用反射可以得到里面的注解信息。 好了接下来看怎么使用我们的这个自定义的注解!

public class HomeActivity extends AppCompatActivity {
    @MyTag(name = "BMW",size = 100)
    Car car;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        //这里我们要首先注册一下这个类
        AnnotationCar.instance().inject(this);
      //当程序运行的时候这里将会输出该类Car的属性值。
        Log.e("WANG","Car is "+car.toString());
    }
}

是不是很像我们使用过的ButterKnife呢,这里呢我们再这个Activity里面定义了一个Car类的属性,然后再car这个变量上面定义我们的注解,并且给我们的注解赋值。然后我们再onCreate方法里面先初始化我们的注解,然后打印Car类的信息,先来看下结果吧

cn.example.wang.routerdemo E/WANG: Car is Car [name=BMW, size=100]

这样我们的自定义注解就有作用了,好了半天主要的代码就在那个初始化里面。

//自定义的类
/**
 * Created by WANG on 17/11/21.
 */

public class AnnotationCar {
    private static AnnotationCar annotationCar;
    public static AnnotationCar instance(){
        synchronized (AnnotationCar.class){
            if(annotationCar == null){
                annotationCar = new AnnotationCar();
            }
            return annotationCar;
        }
    }

    public void inject(Object o){
        Class<?> aClass = o.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field:declaredFields) {
            if(field.getName().equals("car") && field.isAnnotationPresent(MyTag.class)) {
                MyTag annotation = field.getAnnotation(MyTag.class);
                Class<?> type = field.getType();
                if(Car.class.equals(type)) {
                    try {
                        field.setAccessible(true);
                        field.set(o, new Car(annotation.name(), annotation.size()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

这就说明了为什么注解和反射是同时进入我们的知识圈里面的吧!这里呢我们先获取到类里面所有的属性,然后去找到被我们的注解MyTag修饰的那个属性,然后找到之后,先取我们注解里面的值,然后赋值给我们类里面的属性!这样我们就用注解去初始化了一个属性值,嘻嘻这里就结束了啊!

结束语

例子很简单,看完之后是不是也会写一个类似ButterKnife的效果了呢,有什么问题请留言给我,我会实时为你解答的!

本文分享自微信公众号 - Android先生(cyg_24kshign)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flutter组件学习(一)—— Text组件

    之前说会给大家一一讲解 Flutter 中的组件,今天咱们就从 Text 组件开始,无图言X,先上图:

    用户2802329
  • Dagger2神器入门(二)

    在Dagger2神器入门(一)中,我们了解了什么是依赖注入,那么在这一章中,我们将逐渐入门Dagger2。接下来我们会通过demo形式给大家展现Dagger2的...

    用户2802329
  • Flutter组件学习(三)—— 输入框TextFiled

    Google 前两天发布了 Flutter 1.0 正式版本,正式版发布之后,LZ身边越来越多的人都开始入坑了,不得不说 Flutter 框架的魅力还是很吸引人...

    用户2802329
  • Spring 注解@Transactional

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

  • Java 注解 Annotation

    java404
  • 深入浅出Java注解

    注解对于开发人员来讲既熟悉又陌生,熟悉是因为只要你是做开发,都会用到注解(常见的@Override);陌生是因为即使不使用注解也照常能够进行开发...

    open
  • Java编程之反射中的注解详解

    “注解”这个词,可谓是在Java编程中出镜率比较高,而且也是一个老生常谈的话题。我们之前在聊Spring相关的东西时,注解是无处不在,之前我们简单的聊过一些“注...

    lizelu
  • Java注解总结(史上最全,有这一篇就够了)

    Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java...

    Java_老男孩
  • JAVA 注解的基本原理

    来源:https://juejin.im/post/5b45bd715188251b3a1db54f

    芋道源码
  • 夯实Java基础系列15:Java注解简介和最佳实践

    Annotation 中文译过来就是注解、标释的意思,在 Java 中注解是一个很重要的知识点,但经常还是有点让新手不容易理解。

    Java技术江湖

扫码关注云+社区

领取腾讯云代金券