0%

Java——注解

何为注解

  • 注解(也被称为元数据),它为我们在代码中添加信息提供了一种形式化的方法,使我们可以在某个时刻非常方便地使用这些数据。它使得我i们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息,它可以用来生成描述符文件,甚至可以是新的类定义,这样有助于减轻编写“样板”代码的负担。
  • 通过注解我们可以将这些元数据保存在Java源代码中,同时,注解的优点还包括:更加干净易读的代码以及编译器类型检查等。我们还可以自定义注解,并按自己的方式使用它们。

内置的注解

  • 在JavaSE中内置了三种java.lang包下的注解:
    1. @Override:表示当前的方法定义将覆盖超类中的方法
    2. @Deprecated:表示发出警告信息
    3. @SuppressWarnings:关闭不当的编译器警告信息
  • Java还另外提供了四种注解,专门负责新注解的创建

注解的基本语法

基本注解

  • 下面就是一个简单的注解的定义,可以看到注解的定义很像接口的定义,但注解使用的是@interface来定义的,与其他的Java接口一样,注解也会被编译成class文件
1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
  • 在定义注解时,需要一些元注解,如@Target@Retention@Target表示定义好的注解将会被应用在什么地方;@Retention则表示该注解在哪一个级别可用。
  • 在注解中,一般都会包含一些元素来表示某些值,当分析处理注解时,程序可以利用这些值,而没有元素的注解称为标记注解,就像上面的@Test一样。

定义元素

  • 在注解中,可以用定义接口的方式一样来定义注解的内容,而这些内容称为元素,如下面代码中的id和description,它们的定义类似于方法的定义,只是跟接口一样,是一个抽象的方法。在这里description元素有一个default值,如果在注解某个方法没有给出description的值,则该注解的处理器会使用默认值。
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.muchlab.anntation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}

注解的使用

  • 注解的元素在使用时表现为名—值对的形式,并将其置于@xxx声明之后的括号内
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.muchlab.anntation;

import com.sun.deploy.util.StringUtils;

public class PasswordUtils {
@UseCase(id=47, description = "Password is required.")
public boolean validatePassword(String password){
return password.matches("\\w*\\d\\w*");
}
@UseCase(id = 48)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
}
}

元注解

  • JavaSE内置了四种元注解:
注解 含义
@Target 表示定义好的注解将会被应用在什么地方;
CONSTRUCTOR:构造器声明
FIELD:域声明(包括enum实例)
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口、注解或enum声明
@Retention 示该注解在哪一个级别可用;
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被JVM丢弃
RUNTIME:VM在运行期会保留注解,因此可以通过反射机制来读取注解的信息,一般情况下都会使用这个值
@Documented 将此注解包含在Javadoc中
@Inherited 允许子类继承父类中的注解

注解处理器

  • 在大多数时候,我们都会定义自己的注解,然后编写自己的处理器来出了它们,如果没有用来读取注解的工具,则注解将没有多大用处。所以使用注解的过程中,很重要的一部分是创建与使用注解处理器
  • 下面是一个注解处理器,它将读取PassUntils类,查找@UseCase标记,并通过注解的元素进行一些操作。下面的程序使用了两个反射方法:getDeclaredMethodsgetAnnotation,它们都属于AnnotatedElement接口(Class、Field、Method都实现了该接口),getAnnotation需要提供注解的Class对象,它将返回方法的注解对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.muchlab.anntation;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UseCaseTracker {
public static void trackUseCases(List<Integer> useCases, Class<?> cl){
for (Method method : cl.getDeclaredMethods()) {
//返回指定类型的注解对象,如果方法没有该注解,将返回null
UseCase uc = method.getAnnotation(UseCase.class);
if (uc!=null){
/**
* 其中id为47的方法添加了description,而id为48的方法没有添加description
*/
System.out.println("Found Use Case "+uc.id()+" "+uc.description());
useCases.remove(new Integer(uc.id()));
}
for (Integer useCase : useCases) {
System.out.println("Warning:Missing use case:"+useCase);
}
}
}

public static void main(String[] args) {
final ArrayList<Integer> useCases = new ArrayList<>();
Collections.addAll(useCases, 47, 48, 49);
trackUseCases(useCases, PasswordUtils.class);
}
}

注解元素

  • 注解中允许的元素类型如下:
    1. 所有的基本类型,不包括其包装类
    2. String
    3. Class
    4. enum
    5. Annotation
    6. 以上类型的数组
  • 默认值的限制:
    1. 元素不能有不确定的值,即元素要么具有默认值,要么在使用注解时提供元素的值
    2. 不能以null作为默认值

参考资料:Java编程思想

-------------本文结束感谢您的阅读-------------