Java中的注解

什么是注解?

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

非常官方的解释,第一次看到使人一脸懵逼!

咱们可以把它翻译翻译,翻译成人话:注解是使用在Java代码上的,相当于是给代码做了一个标记,这些代码可以是类、接口、枚举类、成员变量、方法等等。

这样就可以解释为什么注解是元数据,注解就是Java源代码的元数据。使用注解可以对你编写的源代码做一些描述。

比如说我们经常见到的一个注解@Override

@Override
public String toString() {
    return "This is String Representation of current object.";
}

上面的代码中,我重写了toString()方法并使用了@Override注解。但是,即使我不使用@Override注解标记代码,程序也能够正常执行。

那么,该注解表示什么?这么写有什么好处吗?事实上,@Override告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。

如果我不小心拼写错误,例如将toString()写成了toStrring(){double r},而且我也没有使用@Override注解,那程序依然能编译运行。但运行结果会和我期望的大不相同。现在我们了解了什么是注解,并且使用注解有助于阅读程序。

注解的定义

public @interface MyAnnotation{
	
}

这样就定义了一个简单的注解,不过,要想注解能够正常工作,还需要介绍一下一个新的概念那就是元注解。

元注解

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。用来描述我们自定义的注解的一些信息。

元注解有 @Retention、@Documented、@Target、@Inherited、@Reapeatable 5 种。

  • @Documented:注解是否将包含在JavaDoc中
  • @Retention:注解的留存期,注解能存活到什么时候
  • @Target:注解用于什么地方(代码中的什么元素)
  • @Inherited:是否允许子类继承该注解
  • @Reapeatable:可以重复注解

@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。

@Retention– 定义该注解的生命周期。

  • RetentionPolicy.SOURCE – 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  • RetentionPolicy.CLASS – 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
  • RetentionPolicy.RUNTIME– 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

@Target – 表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。需要说明的是:属性的注解是兼容的,如果你想给7个属性都添加注解,仅仅排除一个属性,那么你需要在定义target包含所有的属性。

  • ElementType.TYPE:用于描述类、接口或enum声明
  • ElementType.FIELD:用于描述实例变量
  • ElementType.METHOD
  • ElementType.PARAMETER
  • ElementType.CONSTRUCTOR
  • ElementType.LOCAL_VARIABLE
  • ElementType.ANNOTATION_TYPE 另一个注释
  • ElementType.PACKAGE 用于记录java文件的package信息

@Inherited – 定义该注释和子类的关系

注解的内部定义

Annotations只支持基本类型、String及枚举类型。注解中所有的属性被定义成方法,并允许提供默认值。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnnotation {
  public enum Status{OPEN, CLOSE}
  Status status() default Status.CLOSE;
  //枚举类型
  Day day() default Day.MON;
  //String类型
  String value();
  //基本类型
  int i() default 0;
}

如果注解中只有一个属性,可以直接命名为“value”,使用时无需再标明属性名。

public @interface MyAnnotation{
	String value();
}

使用时:

@MyAnnotation("test")
public class Test{
	
}

重复注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
//可重复的注解
@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {
  public enum Status{OPEN, CLOSE}
  Status status() default Status.CLOSE;
  //枚举类型
  Day day() default Day.MON;
  //String类型
  String value();
  //基本类型
  int i() default 0;
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotations{
  MyAnnotation[] value();
}

重复注解的使用、获取

@MyAnnotation("abc")
@MyAnnotation("xyz")
public class Test {
  public static void main(String[] args) {
    Class<Test> clazz = Test.class;
    Annotation[] annotations = clazz.getAnnotations();
    System.out.println(Arrays.toString(annotations));
  }
}

输出结果:
[@loong.anno.MyAnnotations(value=[@loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=abc), @loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=xyz)])]

换种方法使用

@MyAnnotations({
        @MyAnnotation("abc"),
        @MyAnnotation("xyz")
})
public class Test {
  public static void main(String[] args) {
    Class<Test> clazz = Test.class;
    Annotation[] annotations = clazz.getAnnotations();
    System.out.println(Arrays.toString(annotations));
  }
}

输出结果:
[@loong.anno.MyAnnotations(value=[@loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=abc), @loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=xyz)])]

可见输出结果都是一样的,@Repeatable是写重复注解时的一个语法糖

使用注解

主要是在Runtime时期获取注解

上一篇:简单写了个扫雷游戏,有问题的话请多指教


下一篇:注解(Annotation)