注解与依赖注入


注解
什么是注解?
        注解是一种元数据(描述数据的数据),它是一种描述作用,在编译前和运行时获取注解信息。
网上常说的注解。基本是运行时注解。而所说的注解会影响性能。则是指的此类型的注解。因为运行时注解的解析。完全依赖于反射。而反射的效率。是比原生的慢的。特别是对于原先的老机型。本来配置就低。运行就卡。再使用过多注解。运行时去反射解析。就导致运行效率更慢了。这也就是网上老司机们所说的。注解会影响性能的主因了。但是其实这个基本可以不用去管。现在的手机运行得那么6。你就是用注解。那其实也影响不了多少性能的。

而对于编译时注解。就不一样了。我们都知道。我们写的java文件。会先经过编译。将java文件编译成.class文件。再对class文件进行打包等一系列处理。生成apk。最终才运行到我们的手机上。所以编译时注解。是在java编译生成.class文件这一步进行的操作。根本和我们的apk运行。没半毛钱关系。所以效率问题也就无从说起了。
为什么要使用注解
比如这段代码

@Override
public String toString() {
    return "hello moto";
}

上述代码中我们重写了tostring方法并且加了override注解,但是我们即便不加overridde注解程序也能完成运行,那么这个注解是什么,有了它好处又在哪里?事实上,这个注解就是告诉编译器这是个重写方法,如果父类不存在该方法,编译器会报错,提示该方法没有父类的方法,如果我们不小心把toString写成toStting,而且我们也没有使用@Override注解,那么程序也能完成的运行,
但是结果却不是我们期望的,不同的注解有不同的含义和功能,@Override起了帮我们在编译期校验的功能。

自定义注解
现在我们有个问题就是自己如果通过注解来传入相应的内容,使用“key=value”这种格式

    @BindView(data = "20170729",value = "zew")
    public Button btn1;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
    String value();
    String data();
}

比如说我们自定义的依赖注入butterknife。

@BindView(R.id.tv_xinyongmao)
    public TextView xinyongmao;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
    //属性叫 value ,在使用时可以直接传参数即可,不必显式的指明键值对,是一种快捷方法
    int value();
}

当注解参数只有一个的时候我们可以直接使用value(),这样在使用时可以使用快捷方式--直接传值,而不需要声明他的属性名称

java内置了哪些注解
5 个用于通知编译器信息的注解:
@Override :空注解,用于标记那些覆盖父类方法的方法,如果父类没有这个方法,或者复写的方法访问权限比父类的权限小,编译器就会报错
@Deprecated : 空注解,用于标记那些不应该被使用的代码,如果使用了过时的代码,编译器会发出警告
@SafeVarargs : 空注解,(varargs 可变参数)用于标记构造函数或者方法,通知编译器,这里的可变参数相关的操作保证安全
@FunctionInterface : Java SE 8 出现的,用于通知编译器,这个类型是 function 接口
@SuppressWarning:抑制错误,可以用于标记整个类、某个方法、某个属性或者某个参数,用于告诉编译器这个代码是安全的,不必警告
强烈建议最小范围使用这个注解,一旦你在一个比较大的范围抑制错误,可能会把真正的问题掩盖了

4 个用于修饰注解的注解:

修饰其他注解的注解称为“元注解”。
@Documented:让注解信息出现在 document 中
@Retention : 指出注解如何存储,支持以下三种参数
RetentionPolicy.SOURCE : 注解只保留在源码中,编译时会忽略
RetentionPolicy.CLASS : 更高一级,编译时被编译器保留,但是运行时会被 JVM 忽略
RetentionPolicy.RUNTIME : 最高级,运行时会被保留,可以被运行时访问
@Target :指出注解作用于(修饰)什么对象,支持以下几种参数
ElementType.TYPE : 作用于任何类、接口、枚举
ElementType.FIELD : 作用于一个域或者属性
ElementType.METHOD : 作用于一个方法
ElementType.PARAMTER : 作用于参数
ElementType.CONSTRUCTOR : 作用于构造函数
ElementType.LOCAL_VARIABLE : 作用于本地变量
ElementType. ANNOTATION_TYPE : 作用于注解
ElementType.PACKAGE : 作用于包
@Inherited :当前注解是否可以继承

4 个用于修饰注解的注解:

修饰其他注解的注解称为“元注解”。
@Documented:让注解信息出现在 document 中
@Retention : 指出注解如何存储,支持以下三种参数
RetentionPolicy.SOURCE : 注解只保留在源码中,编译时会忽略
RetentionPolicy.CLASS : 更高一级,编译时被编译器保留,但是运行时会被 JVM 忽略
RetentionPolicy.RUNTIME : 最高级,运行时会被保留,可以被运行时访问
@Target :指出注解作用于(修饰)什么对象,支持以下几种参数
ElementType.TYPE : 作用于任何类、接口、枚举
ElementType.FIELD : 作用于一个域或者属性
ElementType.METHOD : 作用于一个方法
ElementType.PARAMTER : 作用于参数
ElementType.CONSTRUCTOR : 作用于构造函数
ElementType.LOCAL_VARIABLE : 作用于本地变量
ElementType. ANNOTATION_TYPE : 作用于注解
ElementType.PACKAGE : 作用于包
@Inherited :当前注解是否可以继承

注解的作用
注解可以修饰类,方法,参数,具体的使用场景有三种:
1:编译前提示信息:注解可以被编译器用来发现错误,或者清除不必要的警告;
2:编译时生成代码:一些处理器可以在编译时根据注解信息生成代码,这个很重要,很多第三方框架都是基于这个特性进行的。下面我要解释的我的依赖注入框架也是基于apt的生成的代码完成依赖注入。
3:运行时处理,我们可以在运行时根据注解,通过反射获取到具体的值,然后做一些操作,下面我要解释的框架了也有基于运行时的反射获取值的操作,想了解的待会代码见。

注解的用法:
自定义注解:规定处理对象的类型(@Target),保存阶段(@Retention),以及包含的值( int value();)。

使用注解修饰我们想处理的类,方法和字段,
读取注解:如何读取注解,我们有专门的注解处理器去帮我们读取。

而注解处理器分为两种:
运行时处理器
编译时处理器

1:运行时处理器:
运行时处理器需要使用注解+反射,非常的简单:
我们先定一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ContentView {
    //属性叫 value ,在使用时可以直接传参数即可,不必显式的指明键值对,是一种快捷方法
    int value();
}

然后用它来修饰一个activity中的属性:

@ContentView(R.layout.activity_annotation)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

在 Activity 中反射获取当前属性使用的注解,拿到注解的值,就可以直接设置布局了:

private void annotationProcess() {
        Class c = this.getClass();
        //遍历所有子类
        for (; c != Context.class; c = c.getSuperclass()) {
            //找到使用 ContentView 注解的类
            ContentView annotation = (ContentView) c.getAnnotation(ContentView.class);
            if (annotation != null) {
                try {   //有可能出错的地方都要 try-catch
                    //获取 注解中的属性值,为 Activity 设置布局
                    this.setContentView(annotation.value());
                } catch (RuntimeException e) {
                    e.printStackTrace();
                }
                return;
            }

        }
    }

但是这种运行时注解有个很大的问题,运行时注解需要使用大量 Java 反射而引起较为严重的性能问题。所以为了避免这个问题我们尽可能的希望这些在编译期完成,接下来一篇我们接着就这个引申介绍一下编译时注解,以及编译期注入和编译期进行路由框架的实现。。。
1.3感悟
     

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值