学习笔记:Java之注解基础

学习这个知识需要有一些反射的基础


内置的常用注解

注解可以从源文件,class文件或在运动时反射的多种方式读取,对应的等级是SOURCE, CLASS, RUNTIME

Java中已经为我们提供了一些注解,其中常用的有:

  • @Override 表示重载方法
  • @Deprecated 表示其修饰的对象不建议使用
  • @SuppressWarnings 表示忽略其修饰的对象出现的warning

几个简单的例子

使用@Override修饰,如果重载的方法名写错的话在编译阶段编译器会报错

1
2
3
4
5
6
public class Basic {
@Override
public String toString() {
return "Basic";
}
}

使用@Deprecated修饰,则在运行时会给出一个过时warning,比较智能的编辑器也会给出相应的警告

1
2
3
4
5
6
public class Basic {
@Deprecated
public String func() {
return "Basic";
}
}

使用@SuppressWarnings修饰,编译器在编译的时候不会显示出一些warning,比较智能的编辑器亦是如此

1
2
3
4
5
6
@SuppressWarnings({"unchecked"})
public void useDeprecated() {
Map map = new TreeMap();
map.put("hello", new Date());
System.out.println(map.get("hello"));
}

自己定义一个注释

自己定义的注释隐含继承了 java.lang.annotation.Annotation 接口,一个例子如下

1
2
3
public @interface AnnotationTest {
String value() default "Hello";
}

value()为注释内的成员,可以设置默认值,这里设置为”Hello”,当然,也可以没有成员

在使用的时候如下

1
2
3
4
5
6
@AnnotationTest(value = "hello")
public class AnnotationTestClass {
@AnnotationTest(value = "hello")
public void func() {
}
}

当然,如果注释内没有成员的话那么括号就可以不写了,也可以增加注释的成员

1
2
3
4
5
6
7
8
public @interface AnnotationTest {
String value() default "Hello";
EnumTest value2();
}

enum EnumTest {
Hello, World, Welcome
}

那么使用的使用就要这样了

1
2
3
4
5
public class AnnotationTestClass {
@AnnotationTest(value = "hello", value2 = EnumTest.Hello)
public void func() {
}
}

指定注释生效的阶段

当然,也有可以修饰注释的注释,比如 java.lang.annotation.Retention,用于标识被修饰注释的生效时期,设定的值有三种,有枚举类 java.lang.annotation.RetentionPolicy 指定,如下

  • SOURCE 被编译器忽视 @SuppressWarnings @Override
  • CLASS 存储于class档中,但运行时被VM忽略
  • RUNTIME 存储于class档中,运行时可有VM读入 @Deprecated

注意,第三个可以使用反射的技术调用其中的值,例子如下

先声明一个自定义的注解

1
2
3
4
5
// 表示其在运行阶段有效
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "Hello world";
}

如果用来修饰方法 methodWithAnno 的话,运行时可以使用反射技术调用到MyAnnotation中的value值

当然,Method,Class,Constructor都可以调用到,还可以判断是否存在这个注解

  • isAnnotationPresent() 判断该注解是否存在
  • getAnnotation() 调用这个注解
  • getDeclaredAnnotations() 获取所有 RetentionPolicyRUNTIME 的注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Retention {

@MyAnnotation(value = "Hello world method!")
public void methodWithAnno() {
System.out.println("With annotation method!");
}

public static void main(String[] args) throws Exception {
// 使用反射
Class<Retention> c1 = Retention.class;

// 判断类的方法是否有相应注解
Method method = c1.getMethod("methodWithAnno");
if (method.isAnnotationPresent(MyAnnotation.class)) {
method.invoke(new Retention());
}

// 获取annotation的值
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String value = myAnnotation.value();
System.out.println(value);
}
}

指定注解修饰的对象

可以使用 java.lang.annotation.Target 修饰自定义的注解指明其可以修饰的对象,类型有枚举类 java.lang.annotation.ElementType 定义,比较多,可以自行查看其源码,这里举一个例子,使自定义的注解只能修饰类的方法

1
2
3
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}

如果用它修饰别的对象,比如说类(class)编译器就会报错


学习来源

需翻墙