谈起注解和反射大部分初学者容易一脸懵逼,这是为何呢?我想主要有两方面的原因:1、相当一部分人工作中开发时很少用到,没有实践过只是看看的话,80%的人过会就忘了,如何注解像集合框架一样大家每天都会用到的话或许大家就不会觉得这东西有啥可神秘的了 2、注解和反射这两部分的知识网络上讲解的并不多也被传的很邪乎的样子,比较系统性的资源较少 。所以很多人都持保守态度,这篇文章将从以下几个方面讲解注解相关的知识,不包含元注解相关知识,只对自定义注解进行说明。,如果你是一个真正热衷技术的人希望你能静下心来看完。
1、注解的定义(注解到底是个什么东西?)
2、代码解释 (亲手写一个注解)
3、注解的提取
1、注解的定义:
注解到底是什么呢?先来看看百度百科的 定义:
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。 它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
说实话定义的很准确不过太抽象了,但是从中可以找到一些关键语句如 “代码级别的说明”、“注释” 等。这就说明了注释其实和我们平时写的 "/** */"的注释的作用是一样的:不会对我们的代码产生任何影响,如果你不去处理它的话。举一个比较有说明性的例子:我们是一个人,但是我们可能有多个职业,比如说教师、工人、农民、学生。同样一个人也可能既是农民,又是教师。在这里的 “人”可以看做是我们的代码,教师、工人、农民、学生等一系列的职业就是注解,像一个个标签一样贴在我们的人身上,当然你也可以没有标签就是一个普通人,就算你有标签,你是一个农民教师,如果你不说也没人知道,不会对你产生任何影响,说到这里大家明白了?
2、注解的代码实现:关于注解的定义和所有属性就直接看下面的代码好了
1 package com.daihui.quartz; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Retention(RetentionPolicy.RUNTIME) 9 /** 10 *Retention:保留期,说明我们的注解的生命周期。 11 * RetentionPolicy常用取值: 12 * SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 13 * CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。 14 * RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。 15 */ 16 @Target(ElementType.ANNOTATION_TYPE) 17 /** 18 * Target:注解的作用域。定义我们的注解可以在哪些地方使用。 19 * ElementType常用取值: 20 * TYPE:可以给一个类型进行注解,比如类、接口、枚举 21 * FIELD:标记属性 22 * METHOD:标记方法 23 * PARAMETER:标记方法内参数 24 * CONSTRUCTOR:标记构造方法 25 * LOCAL_VARIABLE:标记本地变量 26 * ANNOTATION_TYPE:可以注释到另一个注解上即嵌套注解 27 * PACKAGE:标记包 28 */ 29 //注解定义和接口类似但是需要用 @ 符号修饰 30 public @interface Teacher { 31 //接下来我们可以定义注解的属性,即注解的成员变量 32 //注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明, 33 //其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。如下: 34 String id() ; 35 36 /** 37 * 属性的默认值需要用 default 关键字指定并且类型必须是 38 * 8 种基本数据类型外加 类、接口、注解及它们的数组。 39 */ 40 String profession() default "语文"; 41 }
3、既然我们自定义了注解,当然要使用并提取我们定义的注解的信息了,这里我们需要用到反射相关的知识来提取注解信息:
package com.daihui.quartz; import java.lang.annotation.ElementType; import java.lang.annotation.Target; /** * package-name: com.daihui.quartz * project-name: quartz * function : * @author daihui * @since 2018/3/31 0031 23:13 */ //在这里我们使用了我们自定义的注解标记我们这个人是是一个教师,并且是一个教英语的教师 @Teacher(type = 1,profession = "英语") public class Person { public static void main(String[] args) { /** *由于我们在上面定义的注解为 @Target (ElementType.TYPE),即作用于类上面 *所以我们这里使用 Class 获取注解的相关信息 */ // isAnnotationPresent(Class<? extends Annotation> annotationClass) 方法判断我们的 person 类是否应用了某个注解 boolean isAnnotationPresent = Person.class.isAnnotationPresent(Teacher.class); System.out.println("isAnnotationPresent:"+isAnnotationPresent); /** * getAnnotation(Class<A> annotationClass) 方法直接获取指定类型的注解 * 或者使用 getAnnotations() 直接获取该类上应用的注解数组 */ Teacher annotation = Person.class.getAnnotation(Teacher.class); System.out.println("type:"+annotation.type()); System.out.println("profession:"+annotation.profession()); } } 运行结果如下: isAnnotationPresent:true type:1 profession:英语
作用于方法或者字段上的注解通用可以获得,但是就不是通过Class了,而是 Field 或者 Method ,在这里就不再赘述了,希望大家能够自己实践一下加深印象
看到了这里或许大家还是不知道注解到底有个啥用?如果你看到了这里请再移步到上面获取注解信息的代码,思考一下:我们获取了这个人的信息知道他是一个教师了,如果你有孩子了那是不是有可能这个教师是你孩子的老师,那么接下来是不是可以和老师谈谈人生?
总结:
- 如果注解难于理解,你就把它类同于标签,标签为了解释事物,注解为了解释代码。
- 注解的创建如同接口,只是多了个 @ 符号。
- 注解的属性包含8种基本类型以及类、接口、注解和他们的数组
- 注解的提取需要借助于 Java 的反射技术,由于反射比较慢,因此使用注解时也需要谨慎计较时间成本。