内容简介:原文发于微信公众号jzman-blog,欢迎关注交流。Java 注解(Annotation)又称之为 Java 标注、元数据,是 Java 1.5 之后加入的一种特殊语法,通过注解可以标注 Java 中的类、方法、属性、参数、包等,可以通过反射原理对这些元数据进行访问,注解的使用不会影响程序的正常运行,只会对编译器警告等辅助工具产生影响。注解的定义使用 @interface 作为关键字,实际上表示自动继承了 java.lang.annotation.Annotation 接口,定义格式参考如下:
原文发于微信公众号jzman-blog,欢迎关注交流。
Java 注解(Annotation)又称之为 Java 标注、元数据,是 Java 1.5 之后加入的一种特殊语法,通过注解可以标注 Java 中的类、方法、属性、参数、包等,可以通过反射原理对这些元数据进行访问,注解的使用不会影响程序的正常运行,只会对编译器警告等辅助 工具 产生影响。
注解功能
- 编译器可以使用注解来检测错误和取消警告;
- 使用注解可以生成特定代码,如 ButtferKnife 使用注解简化 findViewById等;
- 某些注解可以在运行时进行检查和操作。
定义注解
注解的定义使用 @interface 作为关键字,实际上表示自动继承了 java.lang.annotation.Annotation 接口,定义格式参考如下:
@元注解 public @interface AnnotationName{ //配置参数(参数类型 参数名称()) String name() default "hello"; }
配置参数里面的类型包括基本类型、String、class、枚举以及相关类型的数组,可以使用 default 设置配置参数的默认值,定义一个注解具体如下:
@Target(value = {ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface TestDefineAnnotation { String[] name() default "test"; }
内置注解
- @Override
- @Deprecated
- @SuppressWarnings
下面是上面三个内置注解的声明:
//表示当前的方法将覆盖超类中的方法,编译时进行格式检查 @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { } //表示一个类或者是方法不再建议使用,将其标记为过时,但还是可以使用 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); } //表示关闭不当的编译器警告信息 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
根据对上面三个注解的声明来看,@SuppressWarnings 中定义了一个数组,这个数组表示在该注解上具体的目标是那些,如可在 SuppressWarnings 上使用的值,常用的具体如下:
- deprecation:使用了过时的类或方法时的警告
- unused:有未使用的变量时的警告
- unchecked:执行了未检查的转换时的警告
- fallthrough:当 switch 程序块直接通往下一种情况而没有 break 时的警告
- path:在类路径、源文件路径等中有不存在的路径时的警告
- serial:当在可序列化的类上缺少serialVersionUID 定义时的警告
- finally :任何 finally 子句不能正常完成时的警告
- all:关于以上所有情况的警告
下面看一个案例,具体如下:
public void test() { long date = Date.parse("2018-04-22"); }
上面的代码如果使用 eclipse 等其他 IDE 时会出现两个警告,一是使用了过时的 API,二是变量 date 赋值后没有被使用过,警告截图如下:
当然, IDE 会提示是否添加 SuppressWarnings 来取消这些警告,前文中可以看到注解 @SuppressWarnings 的声明中需要配置参数,这个参数是一个数组,数组名称是 value,可以省略这个名称, 具体如下:
//不省略 public void test2() { @SuppressWarnings(value= {"deprecation", "unused"}) long date = Date.parse("2018-04-22"); } //省略 public void test2() { @SuppressWarnings({"deprecation", "unused"}) long date = Date.parse("2018-04-22"); }
来张截图说明一下使用 @SuppressWarnings 的效果,具体如下:
如果只想取消一种警告可以这样写,具体如下:
//第一种 public void test2() { @SuppressWarnings(value = {"deprecation"}) long date = Date.parse("2018-04-22"); System.out.println(date); } //第二种 public void test2() { @SuppressWarnings({"deprecation"}) long date = Date.parse("2018-04-22"); System.out.println(date); }
注意:如果在定义注解的配置参数名称为 value ,那么可以在配置注解时可以省略 value ,反之,使用其他名称,则必须采用第一种方式,要指定配置参数名称。
当然其他注解和 @SuppressWarnings 也比较类似, @Override、@Deprecated 由它们的声明可知直接使用即可,不需要指定具体目标,在其声明注解时用到了 @Documented、@Retention、@Target 等,这些用来注解其他注解的特殊注解称之为元注解,具体请看下文。
元注解
- @Target
- @Retention
- @Documented
- @Inherited
@Target
@Target 用来描述注解的使用范围,它的声明如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
由 @Target 声明可知使用 @Target 注解必须指定具体的 Java 成员,也就是该注解要使用到哪个位置,具体由枚举 ElementType 中定义,具体如下:
public enum ElementType { TYPE, //类、接口、注解、枚举 FIELD, //属性(包括枚举常量) METHOD, //方法 PARAMETER, //参数 CONSTRUCTOR, //构造方法 LOCAL_VARIABLE, //局部变量 ANNOTATION_TYPE,//注解 PACKAGE, //包 /** * 类型注解 * @since 1.8 */ TYPE_PARAMETER, TYPE_USE }
@Retention
@Retention 表示在什么级别保存该注解的信息,它的声明如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
由 @Retention 的声明可知,使用 @Retention 时,必须指定保存celue(RetentionPolicy),具体值如下:
public enum RetentionPolicy { SOURCE, //在编译时会被丢弃,仅仅在源码中存在 CLASS, //默认策略,运行时就会被丢弃,仅仅在 class 文件中 RUNTIME //编译时会将注解信息记录到class文件,运行时任然保留,可以通过反射获取注解信息 }
@Documented和 @Inherited 都没有配置参数,是一种标记注解, @Documented 表示将该注解显示到用户文档中, @Inherited 表示该注解只有使用在类上才会有效,而且该注解会被子类继承。
类型注解
在对元注解的说明中可知从 Java8 开始新增了 类型注解 ,如果在注解 @Target 使用这种注解,表明该注解可以在对应的任何地方使用,如在 @Target 中指定 TYPE_PARAMETER 就可在 自定义类型的声明处 使用该注解,如在 @Target 中指定 TYPE_USE 就可在任何类型前添加该类之间,主要是方便 Java 开发者使用类型注解和相关插件(Checker Framework)来检查来在编译期检查运行时的异常。
下面分别定义指定 TYPE_PARAMETER 和 TYPE_USE 的注解,具体如下:
//1. TYPE_PARAMETER @Target(value = {ElementType.TYPE_PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface TypeParameterAnnotation { String value(); } //2. TYPE_USE @Target(value = ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) public @interface TypeUseAnnotation { }
然后,在下面的案例中使用这两个注解,具体如下:
/** * 测试注解 * @author jzman */ public class TestAnnotation { //... /** * ElementType.TYPE_PARAMETER * 使用在自定义类型声明的时候,如注解@TypeParameterAnnotation * @param <T> */ static class TypeAnnotationA<@TypeParameterAnnotation(value="hello") T>{ /** * ElementType.TYPE_USE * 可以使用在任意类型前面(包含TYPE_PARAMETER) */ //创建实例 MyType myType = new @TypeUseAnnotation MyType(); //对象类型 Object obj = (@TypeUseAnnotation Object) myType; //泛型 ArrayList<@TypeUseAnnotation T> list = new ArrayList<>(); //参数中的类型 public String testA(@TypeUseAnnotation String test) { return "Hello"+test; } //枚举 public void testB(@TypeUseAnnotation Color color) { //... } enum Color{ RED, GREEN, BLUE } } static class MyType{} }
其实注解的语法比较简单,仅仅定义注解对实际开发是没有帮助的,觉得注解只有在运行时通过反射获取注解信息才是最重要的,注解与反射相关的内容会在以后的推文中学习,到此对注解的认识就结束了。
可以选择关注微信公众号:jzman-blog 获取最新更新,一起交流学习!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Spring 注解编程之模式注解
- Java注解之编译时注解
- Java注解之运行时注解
- Java中的注解-自定义注解
- Java注解Annotation与自定义注解详解
- Java 元注解及 Spring 组合注解应用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。