Android开发干货集中营Android技术知识Android开发

Android注解知识点梳理-基础理论

2017-10-26  本文已影响302人  qiujuer

目的

学完本文章你将会明白什么是Annotation,Annotation的基础声明与使用。

什么是注解?

要回答这个问题,我们先来看一个案例。

@Override
public String toString() {
return "This is String.";
}

在上面代码中:@Override 就是一个注解。

那么我现在来回答你什么是注解;注解是从Java1.5版本开始加入Java大家族的,目的是给代码提供一定的注释、标注。Annotation是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符。它是一种由JSR-175标准选择用来描述元数据的一种工具。

起初Annotation的出现是为了简化代码的XML配置与描述,用于简化这一过程。

除了@Override这一注解之外,我们常用的还有:

以上3中是咱们代码中最常见的3中基础注解。

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

@Override 是为了标注方法是复写父类或是实现的接口,那么编译器会为我们在编译时做检测,检查是否在父类或集成的接口中有该方法,已达到避免出错的目的。上面的代码如果我们不加@Override然后改成 toString(int a) 也是可以编译过,但是这就与我们的初心违背了。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

@Deprecated是不受待见的,因为它的出现意味着类或方法是过时的,将要废弃的;我们的代码应当给具有更加优秀的方案替换的老旧的类或方法加上这样的注解,已表明这方法是过时的,使用者应当使用更好的方案。

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}

@SuppressWarnings与上面2者基础注解不同,他具有一个接收值;该值是一个数组。主要的包括:

注解的作用

一般而言注解具有如下作用:

/
**
* @param count Count
* @return String
* @see #start(int)
* @since 1.2.0
*/
public String start(int count) {
return null;
}

注解的语法

上面简单的介绍了注解,而且明白了什么是注解,那么注解该如何声明?

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* @author qiujuer Email:qiujuer@live.cn
* @version 1.0.0
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface JumpUiThread {
JumpType value() default JumpType.AUTO;
}

以上的代码展示了一个完整的自定义注解声明,现在我们来剖析一下。

注解的声明非常简单与接口的方式类似,只不过在interface前面加上一个 “@” 符号即可。至于注解中的JumpType这个仅仅是一个枚举而已,随后将会讲到。

元注解

这个名字很特别,在开篇的时候我们讲了Java的基础注解,OK记住哪些都是 基础注解 ,是Java基础的时候提供的;那么何为元注解?

“用于注解其他注解的注解叫做元注解。” 他的本质也是注解,只不过相对特殊是用于注解其他的注解而已。

  1. @Documented:注解是否将包含在JavaDoc中
  2. @Retention:什么时候使用该注解
  3. @Target:注解用于什么地方
  4. @Inherited:是否允许子类继承该注解
  5. @Repeatable:Java8引入,用于标示可以重复使用的注解

上面的5种注解都是元注解,也都是Java内置具备的;其中最后一项是Java8才加入的。在上面的例子中我们展示了其中3种元注解;下面我们来详细介绍一下。

@Documented

使用@Documented修饰的注解将会在JavaDoc输出的时候保留该注解。一般用于需要让阅读文档的人知道有这个注解,或者是这个注解需要让接手文档的人知晓;注解对逻辑流程具有一定的作用或干扰性。

public class Test {
@Documented
public @interface Annotation1 {

}

public @interface Annotation2 {

}

@Annotation1
public static class Foo1 {

}

@Annotation2
public static class Foo2 {

}
}

对于这个例子我们使用命令 “javadoc Test.java" 生成文档。

可以发现Foo1和Foo2文档并不相同,一个带有注解信息,一个未带有。

@Retention

注解保留到何时,用于约束注解的生命周期,有如下3种选择(枚举):

@Target

注解可以注解的类型,用于约束注解可以应用的地方(方法、参数等)。其枚举ElementType类型如下:

对于最后的:TYPE_PARAMETERTYPE_USE 是Java8所新增的内容,咱们放到后续文章中详细讲解,延伸:Checker Framework。

@Inherited

标示注解是否可继承;这里的集成并不是说注解相互的继承,而是说父类注解能否被子类所感知。

public class Test {
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation1 {

}

@Retention(RetentionPolicy.RUNTIME)
@interface Annotation2 {

}

@Annotation1
static class Foo1 {
}


static class Foo2 extends Foo1 {
}

@Annotation2
static class Foo3 {
}

static class Foo4 extends Foo3 {
}

public static void main(String args[]) {
System.out.println("具有@Inherited:" + Arrays.toString(Foo2.class.getAnnotations()));
System.out.println("没有@Inherited:" + Arrays.toString(Foo4.class.getAnnotations()));
}
}

运行结果:

QIUJUERBOOK:main qiujuer$ java net.qiujuer.jumper.annotation.Test
具有@Inherited:[@net.qiujuer.jumper.annotation.Test$Annotation1()]
没有@Inherited:[]

@Repeatable

该元注解是Java8才引入的注解;用于标示一个注解是否可以重复使用。

@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
String value();
}

// 错误的案例
@Todo("main")
@Todo("show")
static class Foo {
}

在以前你是没法如此使用的,因为编译器不给予编译;那么我想要Todo多条信息怎么办??

@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
String[] value();
}

@Todo({"main", "show"})
static class Foo {
}

OK, 改成数组之后正常了,但是Java8允许更加特殊的方法来使用。

@Repeatable(TodoList.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
String value();
}

@Retention(RetentionPolicy.RUNTIME)
@interface TodoList {
Todo[] value();
}

@Todo("main")
@Todo("show")
static class Foo {
}

上述案例此时是合法的,但是仅在Java8下能成功运行;其原理是通过一个具有Annotation Array的注解(TodoList)来接收数据。其获取的方式咱们也后续另起文章讲解。
好了,到此咱们的注解基础语法讲解完成了;注解是知道是什么了,但是注解如何使用呢?

注解的使用

一般而言注解常常会和反射一起使用;因为注解的信息是存储在AnnotatedElement中,AnnotatedElement是一个接口,实现其接口的有:Class、Constructor、Field、Method、Package

在实际的使用中,我们会使用“java.lang.reflect”包下的一些反射API来获取上述类的实例,通过上述对象的实例我们可以使用AnnotatedElement提供的接口方法来访问标注的Annotaion信息。

一个简单的例子:

public class Test {
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationSuper {
}

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationSuperWithInherited {
}

@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationChild {
}

@AnnotationSuperWithInherited
@AnnotationSuper
static class FooSuper {
}

@AnnotationChild
static class FooChild extends FooSuper {
}

public static void main(String args[]) {
print(FooChild.class);
print(FooSuper.class);
}

private static void print(Class clx) {
System.out.println("============" + clx.getSimpleName() + "============");
System.out.println("所有:" + Arrays.toString(clx.getAnnotations()));
System.out.println("当前类上:" + Arrays.toString(clx.getDeclaredAnnotations()));
System.out.println("查询Child:" + clx.getAnnotation(AnnotationChild.class));
System.out.println("查询Super:" + clx.getAnnotation(AnnotationSuper.class));
System.out.println("查询WithInherited:" + clx.getAnnotation(AnnotationSuperWithInherited.class));
System.out.println("判断WithInherited:" + clx.isAnnotationPresent(AnnotationSuperWithInherited.class));
System.out.println("判断Super:" + clx.isAnnotationPresent(AnnotationSuper.class));
}
}

输出内容:

============FooChild============
所有:[@net.qiujuer.jumper.annotation.Test$AnnotationSuperWithInherited(), @net.qiujuer.jumper.annotation.Test$AnnotationChild()]
当前类上:[@net.qiujuer.jumper.annotation.Test$AnnotationChild()]
查询Child:@net.qiujuer.jumper.annotation.Test$AnnotationChild()
查询Super:null
查询WithInherited:@net.qiujuer.jumper.annotation.Test$AnnotationSuperWithInherited()
判断WithInherited:true
判断Super:false
============FooSuper============
所有:[@net.qiujuer.jumper.annotation.Test$AnnotationSuperWithInherited(), @net.qiujuer.jumper.annotation.Test$AnnotationSuper()]
当前类上:[@net.qiujuer.jumper.annotation.Test$AnnotationSuperWithInherited(), @net.qiujuer.jumper.annotation.Test$AnnotationSuper()]
查询Child:null
查询Super:@net.qiujuer.jumper.annotation.Test$AnnotationSuper()
查询WithInherited:@net.qiujuer.jumper.annotation.Test$AnnotationSuperWithInherited()
判断WithInherited:true
判断Super:true

Process finished with exit code 0

至此,Java注解的基础知识已全部完成,后续文章将讲解注解在运行时态的实战运用和编译时运用。

尾章

看累了吧?自己反复看一下,来一个案例试试~~

END!!!

上一篇下一篇

猜你喜欢

热点阅读