注解(也被称为元数据)为我们在代码中添加信息提供了一种形式的方法,使我们可以在稍后某个时刻非常方便的使用这些数据

Java内置注解(在java.lang包下)

注解

说明

@Override

表示当前的方法定义将覆盖父类中的方法。

如果子类中覆盖父类的方法名称拼写错误,或者方法签名对不上被覆盖的方法,

将发出错误提示

@Deprecated

用于表示某个程序元素(类、方法等)已过时。

如果使用了被@Deprecated修饰的类或方法等,编译器会发出警告。

@SuppressWarnings

关闭不当的编译器警告。

@SafeVarargs

jdk1.7新增。专门为抑制“堆污染”警告提供的

@FunctionalInterface

jdk1.8新增。改注解标记在接口上。“函数式接口”是指仅仅只包含一个抽象方法的

接口。如果一个接口中包含不止一个抽象方法,那么不能使用

@FunctionalInterface,编译会报错。

Java元注解

元注解是负责注解其他注解的注解

注解

说明

@Target

表示该注解可以用在什么地方。参数包括:

ElementType.CONSTRUCTOR:构造器的生命

ElementType.FIELD:域声明(包括enum实例)

ElementType.LOCAL_VARIABLE:局部变量声明

ElementType.METHOD:方法声明

ElementType.PACKAGE:包声明

ElementType.PARAMETER:参数声明

ElementType.TYPE:类、接口(包括注解类型)或enum声明

ElementType.TYPE_PARAMETER:(JDK1.8)新增类型参数声明

ElementType.TYPE_USE:(JDK1.8)使用的类型

@Retention

表示需要在声明级别保存该注解的信息。参数包括:

RetentionPolicy.SOURCE:只保留在源代码中,注解将被编译器丢弃

RetentionPolicy.CLASS:注解在class文件中可用,但会被VM丢弃

RetentionPolicy.RUNTIME:VM在运行期也保留,因此可以通过反射机制读取注解信息

@Documented

将此注解包含在javadoc中

@Inherited

允许子类继承父类的注解

注解的语法与定义形式

在编写自定义注解前,我们需要先了解注解的语法和定义形式。

  • 首先:注解是以@interface 关键字定义的
  • 其次:注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。

例子:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface UserCase {
    
}

这个例子我是定义了一个名字是UserCase的注解,它可以用于方法声明,并且在JVM运行期也保留。上面的注解没有任何功能,接下将通过向注解中加入方法的方式来实现特定的需求。

实现一个简单的自定义注解

功能说明:现在的软件项目大多都是分布式,通过RESTful的接口调取数据,那么我们在使用springMVC制造接口时候就会面临一个API文档问题,现在我们就自定义一个注解,通过在方法上面加入相应的注解内容,自动扫描生成方法的API。

定义注解:

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

/**
 * User: R&M www.rmworking.com/blog
 * Date: 2017/6/12
 * Time: 23:58
 * Test
 * org.thinkInJava.annotations
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiCase {
    public String value();
    public String notes() default "该方法没有说明";
    public String HttpMethod() default "GET";
}

ApiCase类定义了注解提供的接口方法。

注解运用:

public class UserController {

    @ApiCase(value = "用户登录", notes = "用户登录接口")
    public String login(String userName , String passwd){
        //这里是登录逻辑
        return "success";
    }

    @ApiCase(value = "用户注册" , notes = "用户注册接口" ,HttpMethod = "POST")
    public String register(String userName , String passwd){
        return "success";
    }
}

UserController类假设是一个sprinMVC的用户controller,其中login是登录接口,register是注册接口。

注解实现:

public class ApiCaseTracker {

    public static void trackApiCases(Class<?> cl) {
        for (Method m : cl.getDeclaredMethods()) {
            ApiCase api = m.getAnnotation(ApiCase.class);
            if (api != null) {
                System.out.println(cl.getName() + "接口api:[接口值:" + api.value() + "] [接口说明:" + api.notes() + "] [请求类型:" + api.HttpMethod() + "]");
                //useCases.remove(new Integer(uc.id()));
            }
        }

    }

    public static void main(String[] args) {

        trackApiCases(UserController.class);
    }
}

打印结果:

org.thinkInJava.annotations.UserController接口api:[接口值:用户注册] [接口说明:用户注册接口] [请求类型:POST]
org.thinkInJava.annotations.UserController接口api:[接口值:用户登录] [接口说明:用户登录接口] [请求类型:GET]