注解

Java 5之后可以在源代码中嵌入一些补充信息,这种补充信息称为注解(Annotation),例如在方法覆盖中使用过的@Override注解,注解都是@符号开头的。

注解并不能改变程序运行的结果,不会影响程序运行的性能。有些注解可以在编译时给用户提示或警告,有的注解可以在运行时读写字节码文件信息。

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

基本注解

无论是哪一种注解,本质上都一种数据类型,是一种接口类型。到Java 8为止Java SE提供11种内置注解。其中有5是基本注解,它们来自于java.lang包。有6个是元注解 (Meta?Annotation),它们来自于java.lang.annotation包,自定义注解会用到元注解。

@Override

@Override只能用于方法,子类覆盖父类方法(或者实现接口的方法)时可以@Override注解。编译器会检查被@Override注解的方法,确保该方法父类中存在的方法,否则会有编译错误。

如果不使用@Override,那么子类的方法覆盖父类的方法时,子类方法出错也不会报错;而使用了之后错误的子类的方法就会报错。

@Deprecated

@Deprecated用来指示API已经过时了,@Deprecated可以用来注解类、接口、成员方法和成员变量。

就是对于过时的API,使用@Deprecated能够继续编译而不会化横线。

@SuppressWarnings

@SuppressWarnings注解用来抑制编译器警告,如果你确认程序中的警告没有问题,可以不用理会。但是就是不想看到这些警告,可以使用@SuppressWarnings注解消除这些警告。

就是对于那个警告虽然不会报错,但是那个警告如果看的不舒服可以使用@SuppressWarnings来消除警告

@SafeVarargs

当方法的参数个数发生变化的时候,可能因为类型不同而发生警告,而这个时候使用@SafeVarargs就可以抑制编译器警告。

@FunctionalInterface

@FunctionalInterface注解是Java 8增加的,用于接口的注解,声明接口是函数式接口

该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionalInterface,那么编译器会报错

元注解

元注解包括:@Documented、@Target、@Retention、@Inherited、@Repeatable和@Native。元注解是为其他注解进行说明的注解,当自定义一个新的注解类型时,其中可以使用元注解。

  1. @Documented

如果在一个自定义注解中引用@Documented注解,那么该注解可以修饰代码元素(类、接口、成员变量和成员方法等),javadoc等工具可以提取这些注解信息。

  1. @Target

@Target注解用来指定一个新注解的适用目标。@Target注解有一个成员(value)用来设置适用目标,value是java.lang.annotation.ElementType枚举类型的数组,ElementType描述Java程序元素类型,它有10个枚举常量。

ElementType枚举类型中的枚举常量

枚举常量说明
ANNOTATION其他注解类声明
CONSTRUCTOR构造方法声明
FIELD成员变量或常量声明
LOCAL_VARIABLE局部变量声明
METHOD方法声明
PACKAGE包声明
PARAMETER参数声明
TYPE类、接口声明
TYPE_PARAMETER用于泛型中类型参数声明,Java8推出
TYPE_USE用于任何类型的声明,Java8推出
  1. @Retention

@Retention注解用来指定一个新注解的有效范围,@Retention注解有一个成员(value)用来设置保留策略,value是java.lang.annotation.RetentionPolicy枚举类型,RetentionPolicy描述注解保留策略,它有3个枚举常量。

枚举常量说明
SOURCE只适用于Java源代码文件中,此范围最小
CLASS编辑器把注解信息记录在字节码文件中,此范围适中
RUNTIME编辑器把注解信息记录在字节码文件中,并在运行过程中可以读取这些信息,此范围最大
  1. @Inherited

@Inherited注解用来指定一个新注解可以被继承。假定一个类A被该新注解修饰,那么这个A类的子类会继承该新注解。

  1. @Repeatable

@Repeatable注解是Java 8新增加的,它允许在相同的程序元素中重复注释,可重复的注释必须使用@Repeatable进行注释。

  1. @Native

@Native注解一个成员变量,指示这个变量可以被本地代码引用。常常被代码生成工具使用。

自定义注解

自定义注解 就是系统提供的注解不能满足需求,可以自定义注解,注解本质是一种接口,它是java.lang.annotation.Annotation接口的子接口,是引用数据类型。

声明注解

声明自定义注解可以使用@interface关键字实现,,@interface声明一个注解类型,它前面的访问限定修饰符与类一样有两种:公有访问权限和默认访问权限。

注意 关于注解源程序文件与类一样,一个源程序文件中可以声明多个注解,但只能有一个是公有访问权限的,源程序文件命名与公有访问权限的注解名一致。

案例:使用元注解

第一个注解MyAnnotation,它用来修饰类或接口

package Annotation;

import java.lang.annotation.*;
//使用@Documented指定MyAnnotation注解信息可以被javadoc工具读取。
@Documented
//@Target({ ElementType.TYPE })指定MyAnnotation注解用于修饰类和接口等类型。
@Target({ElementType.TYPE})
//@Retention(RetentionPolicy.RUNTIME)指定MyAnnotation注解信息可以在运行时被读取。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    //description是MyAnnotation注解的成员。
    String description();
}

第二个注解MemberAnnotation,它用来类中成员变量和成员方法

package Annotation;

import java.lang.annotation.*;
//@Retention(RetentionPolicy.RUNTIME)指定MemberAnnotation注解信息可以在运 行时被读取。
@Documented
//行@Target({ ElementType.FIELD, ElementType.METHOD })指定 MemberAnnotation注解用于修饰类中成员。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface MemberAnnotation {
    //声明两个成员,type类型是Class<?>,默认值是void.class,void.class是void类型 表示方式。description类型是String,没有设置默认值。
    Class<?> type() default void.class;
    String description();
}
案例:读取运行时注解信息
package Annotation;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class HelloWorld {
    public static void main(String[] args) {
        try {
            //创建Person类对应的Class对象
            Class<?> clz = Class.forName("Annotation.Person");
            //是判断Person类是否存在MyAnnotation注解
            if (clz.isAnnotationPresent(MyAnnotation.class)){
                //getAnnotation方法将MyAnnotation注解实例返回。
                MyAnnotation ann = (MyAnnotation)clz.getAnnotation(MyAnnotation.class);
                //ann.description()表达式读取MyAnnotation注解中description成员内容。
                System.out.printf("类%s,读取注解描述: %s \n", clz.getName(), ann.description());
            }
            //获得所有成员方法对象数组,通过遍历方法对象数组
            Method[] methods = clz.getDeclaredMethods();
            for (Method method : methods) {
                //判断方法中是否存 在MemberAnnotation注解
                if (method.isAnnotationPresent(MemberAnnotation.class)) {
                    //getAnnotation方法将MemberAnnotation注解实 例返回。
                    MemberAnnotation ann = method.getAnnotation(MemberAnnotation.class);
                    //中ann.description()表达式读取MemberAnnotation注解中description成员内容。
                    System.out.printf("方法%s,读取注解描述: %s \n", method.getName(), ann.description());
                }
            }
            //获得所有成员变量对象数组
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(MemberAnnotation.class)) {
                    //判断成员变量中是否存在MemberAnnotation 注解
                    MemberAnnotation ann = field.getAnnotation(MemberAnnotation.class);
                    System.out.printf("成员变量%s,读取注解描述: %s \n", field.getName(), ann.description());
            } }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

本章小结

首先介绍了基本注解,接着介绍了元注解,最后介绍了自定义注解。使用注解能够写出很灵活的代码,注解也特别适合做为使用框架的一种方式。
所以学会使用注解还是很有用的,毕竟这对于上手框架或实现自己的框架都是非常重要的知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值