Java-注解详解

注解-Java使用篇

背景

在之前的Rxjava+ReTrofit+okHttp深入浅出-终极封装和RxBus完全一样的 EventBus中我们频繁的使用了注解,通过注解大大的提升了我们开发的效率,但是很多同学反馈说对里面的使用不是很了解,所以决定对java和android注解的使用做详细的介绍。


版本

在Java中,注解(Annotation)引入始于Java5,用来描述Java代码的元信息,通常情况下注解不会直接影响代码的执行,尽管有些注解可以用来做到影响代码执行


功能

  • 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
  • 跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都 使用了这种配置来减少配置文件的数量
  • 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查 出

基本使用

1.自定义一个注解的使用方法

如@Ety,其中@的意思是告诉编译器这是一个注解。而Ety则是注解的名字。定义一个注解我们需要@interface,使用通常在文件中,代码如下:

public @interface Ety {
}

2.定义完注解对象以后,通常我们还需要给这个对象传递一些属性和方法,代码如下:

public @interface Ety {
    String value();
    String name();
}

3.初始对象方法:

3.1多参数方法

@Ety(value = "v", name = "n")

上述注解的元素名称为value ,设置的值为v,元素名称为name ,设置的值为n;

3.2单一参数方法:假设下载Ety 只有一个String value()方法

@Ety(value = "v")

除了上面的写法以外还可以写成:当且仅当元素名为value,我们也可以简写,即不需要填写元素名

@Ety("v")

4.注解使用

4.1初始完对象以后,后续肯定是如何使用呢?

如果之前有阅读RxBus完全一样的 EventBus原理,肯定知道这里其实是通过java的反射机制来获取注解对象的内容

  @Ety(value = "v", name = "n")
    @OnClick(value = R.id.btn_test)
    void onBtnTestClick(View view) {
        Method[] methods = getClass().getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Ety.class)) {
                Ety ety = method.getAnnotation(Ety.class);
                mTv.append(ety.name()+"---->"+ety.value());
            }
        }
    }

4.2运行效果


Java内置注解

  • @Deprecated

  • @Override

  • @SuppressWarnings

下面分别来介绍它们的区别和使用

@Deprecated

这个注释是一个标记注释。所谓标记注释,就是在源程序中加入这个标记后,并不影响程序的编译,但有时编译器会显示一些警告信息; 那么Deprecated注释是什么意思呢?如果你经常使用eclipse等IDE编写java程序时,可能会经常在属性或方法提示中看到这个词。如果某个类成员的提示中出现了个词,就表示这个并不建议使用这个类成员。因为这个类成员在未来的JDK版本中可能被删除。之所以在现在还保留,是因为给那些已经使用了这些类成员的程序一个缓冲期。如果现在就去了,那么这些程序就无法在新的编译器中编译了;

  • 可以用来标记类,方法,属性。

  • 如果上述三种元素不再使用,使用@Deprecated注解

  • 如果代码使用了@Deprecated注解的类,方法或属性,编译器会进行警告

使用

既然我们知道了Deprecated的作用,我们修改我们的代码,标识value()name()方法

public @interface Ety {
    @Deprecated
    String value();
    @Deprecated
    String name();
}

在Androidstudio中运行会发现,程序依然好用,好像没有任何的区别?其实不然,为了看出效果,我们放入eclipse的编译环境中运行
Java-注解详解_第1张图片

还未运行编译前,eclipse就已经提示我们这两个方法已经弃用,会抛出警告!发生这些变化并不会影响编译,只是提醒一下程序员,这个方法以后是要被删除的,最好别用!


@Override

看着这个想必大家一定不会陌生,我们好像天天都在和这个注解打交道, 这个注释的作用是标识某一个方法是否覆盖了它的父类的方法。那么为什么要标识呢?让我们来看看如果不用Override标识会发生什么事情;

例如ChildClass继承SuperClass,然后覆盖了SuperClassmothead()方法

public class SuperClass {
    public void mothead(){
        Log.e("tag","SuperClass");
    }
}

public class ChildClass extends SuperClass {
    public void mothead() {
        Log.e("tag","--->ChildClass");
    }
}

运行代码:

 @OnClick(value = R.id.btn_ov)
    void onBtnOvClick(View view) {
        SuperClass superClass=new ChildClass();
        superClass.mothead();
    }

结果:

Java-注解详解_第2张图片

修改代码:

public class ChildClass extends SuperClass {
    public void motheadChange() {
        Log.e("tag","--->ChildClass");
    }
}

程序依然没有报错,完全可以正常运行:结果如下

这里写图片描述

实际上在子类中重写父类或接口的方法,@Overide并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字或者是子类的名字,那么之前重写的子类方法将不再属于重写,如果没有@Overide,你将不会察觉到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息


@SuppressWarnings

当我们的一个方法调用了弃用的方法或者进行不安全的类型转换,编译器会生成警告。我们可以为这个方法增加@SuppressWarnings注解,来抑制编译器生成警告

  • @SuppressWarnings用来抑制编译器生成警告信息。

  • 可以修饰的元素为类,方法,方法参数,属性,局部变量

使用代码:

    @SuppressWarnings(value={"deprecation"})
    public void waning(){
    }

@SuppressWarnings 批注接收一个 “value” 变量,该变量是一个字符串数组,它指示将取消的警告。合法字符串的集合随编译器而变化,但在 JDK 上,可以传递给 -Xlint 的是相同的关键字集合(非常方便)。并且要求编译器忽略任何它们不能识别的关键字,这在您使用一些不同的编译器时非常方便。
因为 @SuppressWarnings 批注仅接收一个参数,并为该参数使用了特殊的名称 “value”,所以您可以选择省略 value=,作为一种方便的缩写

    @SuppressWarnings({"deprecation"})
    public void waning(){
    }

注意:使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,我们尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。虽然两个都能抑制编译器生成警告,但是范围越小越好,因为范围大了,不利于我们发现该类下其他方法的警告信息。


修饰的注解类型 API

注解类型 含义
Documented 表示含有该注解类型的元素(带有注释的)会通过javadoc或类似工具进行文档化
Inherited 表示注解类型能被自动继承
Retention 表示注解类型的存活时长
Target 表示注解类型所适用的程序元素的种类

Documented

@Documented:表示拥有该注解的元素可通过javadoc此类的工具进行文档化。该类型应用于注解那些影响客户使用带注释(comment)的元素声明的类型。如果类型声明是用Documented来注解的,这种类型的注解被作为被标注的程序成员的公共API

@Documented
public @interface Ety {
    @Deprecated
    String value();
    @Deprecated
    String name();
}

例如,上面源码定义中有一行@Documented,意思是指当前注解的元素会被javadoc工具进行文档化,那么在查看Java API文档时可查看当该注解元素。


Inherited

@Inherited:表示该注解类型被自动继承,如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类

@Documented
@Inherited
public @interface Ety {
    @Deprecated
    String value();
    @Deprecated
    String name();
}

Retention

@Retention:表示该注解类型的注解保留的时长。当注解类型声明中没有@Retention元注解,则默认保留策略为RetentionPolicy.CLASS。关于保留策略(RetentionPolicy)是枚举类型,共定义3种保留方式

name exp
SOURCE 仅存在Java源文件,经过编译器后便丢弃相应的注解
CLASS 存在Java源文件,以及经编译器后生成的Class字节码文件,但在运行时VM不再保留注释
RUNTIME 存在源文件、编译生成的Class字节码文件,以及保留在运行时VM中,可通过反射性地读取注解

示例代码:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Ety {
    @Deprecated
    String value();
    @Deprecated
    String name();
}

例如,上面源码@Retention的定义中有一行@Retention(RetentionPolicy.RUNTIME),意思是指当前注解的保留策略为RUNTIME,即存在Java源文件,也存在经过编译器编译后的生成的Class字节码文件,同时在运行时虚拟机(VM)中也保留该注解,可通过反射机制获取当前注解内容


Target

表示该注解类型的所使用的程序元素类型。当注解类型声明中没有@Target元注解,则默认为可适用所有的程序元素。如果存在指定的@Target元注解,则编译器强制实施相应的使用限制。关于程序元素(ElementType)是枚举类型,共定义8种程序元素

ElementType exp
TYPE 类、接口(包括注解类型)或枚举声明
CONSTRUCTOR 构造方法声明
PACKAGE 包声明
LOCAL_VARIABLE 局部变量声明
METHOD 方法声明
ANNOTATION_TYPE 注解类型声明
PARAMETER 参数声明
FIELD 字段声明(包括枚举常量)

代码如下

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Ety {
    @Deprecated
    String value();
    @Deprecated
    String name();
}

总结:

Java注解基本就讲解完成了,后续会紧跟着讲解Android注释的详细使用方法,毕竟Android才是我们运用的主要平台!

源码:

传送门-CSDN-戳我


建议:

如果你有任何的问题和建议欢迎加入QQ群告诉我!

你可能感兴趣的:(java,注解-编译运行时注解)