Java注解

Java注解

JDK1.5之后的新特性

1、概念

注解:说明程序的,给计算机看。
注释:用文字描述程序的,给程序员看的。

注解也叫元数据,是一种代码级别的说明,与类、接口、枚举在同一层次。
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、解释。

2、按作用分类

(1)编写文档:通过代码里标识的注解生成文档。如:生成doc文档。
(2)代码分析:通过代码里标识的注解对代码进行分析。如:通过反射。
(3)编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查。如:@Overrider注解

3、Java文档注释

Java支持三种注释:单行注释、多行注释、说明注释

//单行注释的内容
    
    /*
    
    多行注释的内容
    
     */
 /**
     * 计算两整数之和
     * @param a
     * @param b
     * @return
     */
    public int add(int a,int b){
        return a+b;
    }

说明注释允许在程序中嵌入关于程序的信息。可以使用javadoc工具软件生成信息,并输出到HTML文件中。

Javadoc演示

/**
 * 注解javadoc的演示
 * 
 * @author jack
 * @version 3.0
 * @since 1.8
 */
public class AnnotationDemo {
    /**
     * 计算两整数之和
     * @param a
     * @param b
     * @return
     */
    public int add(int a,int b){
        return a+b;
    }

    /**
     * 计算两数之差
     * @param a
     * @param b
     * @return
     */
    public int sub(int a,int b){
        return a-b;
    }
}

将AnnotationDemo.java文件复制保存到新建的文件夹中,在文件夹中打开命令窗口(shift+鼠标右键,打开PowerShell窗口),输入javadoc -encoding utf-8 AnnotationDemo.java命令

如果不指定字符集格式,无法生成文档
在这里插入图片描述
输入正确的命令:
在这里插入图片描述
成功后,会在新建的文件夹下生成一些html、css文件
在这里插入图片描述
打开index.html
在这里插入图片描述
生成的html文档和JDK文档一样,这样我们知道了利用javadoc制作自己的API文档

4、自定义注解

注解以@开头
在idea中new一个自定义注解
在这里插入图片描述

自定义注解的依法格式:

【修饰符列表】 @interface 注解名称{…}

public @interface FirstAnnotation {
}

使用注解:@注解名称 如:@Override

@MyAnnotation
public class Person {
}

5、注解的本质

(1)注解的本质上是一个借口,该借口默认继承Annotation接口
(2)注解的属性就是接口中的抽象方法
(3)注解的属性只能是以下几种:

  • 基本数据类型
    String类型
    枚举类型
    注解类型
    Class类型
    以上类型的一维数组
public @interface MyAnnotation {
    int age();      //int类型
    String name();  //String类型
    Role role();   //枚举类型
    String[] address();  //String类型的数组
}

验证注解的本质

编译(javac)MyAnnotation.java文件,产生MyAnnotation.class文件,再反编译(javap)字节码文件

在这里插入图片描述

public interface MyAnnotation extends Annotation{
}

可以看到,自定义的注解本质上是一个接口,并且继承java.lang.Annotation接口

6、使用自定义注解

(1)在注解中定义了属性,在使用时需要给属性赋值

@MyAnnotation(age=20,name = "张三",role = Role.STUDENT,address = {"北京市","上海市"})
public class Person {
}

(2)数组赋值时,值用大括号{ }包裹,如果数组中只有一个值时,则大括号可以省略。

@MyAnnotation(age=20,name = "张三",role = Role.STUDENT,address = "北京市")
public class Person {
}

(3)如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行属性赋值

public @interface MyAnnotation {
    int age() default 23;      //int类型
    String name() default "";  //String类型
    Role role();   //枚举类型
    String[] address();  //String类型的数组
}
@MyAnnotation(role = Role.STUDENT,address = "北京市")
public class Person {
}

(4)如果只有一个属性需要赋值,并且属性名称为value,则value可以省略,直接定义值即可

public @interface MyAnnotation {
   int age() default 23;
   String address() default "";
   String value();
}


@MyAnnotation("张三")
public class Person {
}

上面的例子中,age属性和address属性已经初始化默认值,只剩下value属性需要赋值,则不用再写成@MyAnnotation(value=“张三”),可以省略为@MyAnnotation(“张三”)。

7、元注解

用于标注在注解上的注解称为元注解

常见的有四个:

  • @Target:用来描述“被标注的注解”可以出现在哪些位置上。
    @Retention:用来描述“被标注的注解”被保留的阶段。
    @Document:用来描述“被标注的注解”是否能被抽取到API文档。
    @Inherited:用来描述“被标注的注解”是否被子类继承

① @Target

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

@Target只有一个属性value,value属性的类型为ElementType类型的数组,ElementType是一个枚举类

public enum ElementType {
    TYPE,                  // 用在类、接口(包括注解类型)、枚举类型上
    FIELD,                 // 属性类型(包括枚举常量上)
    METHOD,                // 方法类型上
    PARAMETER,             // 正式参数上
    CONSTRUCTOR,            // 构造器上
    LOCAL_VARIABLE,        // 局部变量上
    ANNOTATION_TYPE,        // 注解类型上
    PACKAGE,                // 包上
    TYPE_PARAMETER,         // 输入参数声明,从1.8版本才有
    TYPE_USE                // 使用一种类型,从1.8版本才有
}

② @Retention

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

@Retention只有一个属性value,value属性的类型为RetentionPolicy,RetentionPolicy是一个枚举类,其源码:

public enum RetentionPolicy { 
    SOURCE,
    CLASS,
    RUNTIME
}

@Retention(RetetionPolicy.SOURCE):表示被该注解标注的注解只被保留在java源文件中。编译时直接丢弃这个注解。
@Retention(RetetionPolicy.CLASS):表示被该注解标注的注解会被保留在class文件中。运行Java程序时,JVM不会保留这个注解。
@Retention(RetetionPolicy.CLASS):表示被该注解标注的注解会被保留在class文件中。并且可以被反射机制读取到。

③ @Documented

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

④ @Inherited

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

8、JDK常用内置注解

(1)@Override:检测被该注解标注的内容是否是继承自父类(或实现于父接口)的。
源码:

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

通过看源码发现:@Override注解只能用在方法上
(2)@Deprecated:被该注解标注的内容,表示已过时。
源码:

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

在之前学习过的Date类中,大多数方法已过时。
(3)@SuppressWarnings :压制警告
源码:

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

@SuppressWarnings(“all”)可以消除所有警告,一般传递参数all

9、使用反射获取注解信息

需求:创建一个自定义注解,在Person类上及Person的方法上使用注解,在测试类中通过反射获取标注在Person类和方法上的注解信息。
注意:自定义注解必须用@Retention(RetentionPolicy.RUNTIME)标注,这样自定义注解才能被反射机制读取到。

@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfo {
    int age();
    String name();
}
@PersonInfo(age=20,name="张三")
public class Person {

    @PersonInfo(age=30,name="李四")
    public void eat(){
        System.out.println("run方法执行了.....");
    }
}

测试类:

import java.lang.reflect.Method;

public class ReflectPersonInfo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //获取Person类对象
        Class<?> aClass = Class.forName("cn.itcast.annotation.Person");

        //获取标注在Person类上的@PersonInfo注解信息
        if(aClass.isAnnotationPresent(PersonInfo.class)){    //判断Person类上是否有@PersonInfo注解标注
            //获取注解对象
            PersonInfo personInfo = aClass.getAnnotation(PersonInfo.class);

            //打印标注在Person类上的@PersonInfo注解信息
            System.out.println(personInfo.age());
            System.out.println(personInfo.name());
        }

        System.out.println("----------------------------");
        
        //获取标注在Person类的方法上的@Person注解信息
        Method eat = aClass.getDeclaredMethod("eat");   //获取Person类的eat方法对象
        if(eat.isAnnotationPresent(PersonInfo.class)){        //判断Person类的eat方法上是否有@PersonInfo注解标注
            //获取标注在eat方法上的注解对象
            PersonInfo personInfo = eat.getAnnotation(PersonInfo.class);

            //打印标注在Person类中的eat()方法上的注解信息
            System.out.println(personInfo.name());
            System.out.println(personInfo.age());
        }
    }
}

测试结果:
在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页