网站首页 > 技术教程 正文
第十六章、Annotation
在JDK1.5之后增加的一个新特性,这种特性被称为元数据特性,在JDK1.5之后称为注释,即:使用注释的方式加入一些程序的信息。
java.lang.annotation.Annotation接口是所有的Annotation都必须实现的接口。
16-1、Annotation——系统内建Annotation
在JDK1.5之后,系统中已经建立了如下的三个内建的Annotation类型,用户直接使用即可:
·@Override:覆写的Annotation
·@Deprecated:不赞成使用的Annotation
·@SuppressWarnings:压制安全警告的Annotation
NO | Annotation | JAVA中的声明 |
1 | @Override | @Target(value=METHOD) @Retention(value=SOURCE) public @interface Override |
2 | @Deprecated | @Documented @Retention(value=RUNTIME) public @interface Deprecated |
3 | @SuppressWarnings | @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings |
16-1-1、@Override
Override表示方法覆写的正确性,例如现在有如下一段代码:
class Person{ public String getInfo(){ // 取得信息 return "这是一个Person类。" ; } }; class Student extends Person{ // 继承此类 public String getinfo(){ // 覆写方法 return "这是一个Student类。" ; } }; public class OverrideAnnotationDemo01{ public static void main(String args[]){ Person per = new Student() ; System.out.println(per.getInfo()) ; // 输出信息 } }; |
此时,可能存在某种失误,将方法名称编写错误:
class Person{ public String getInfo(){ // 取得信息 return "这是一个Person类。" ; } }; class Student extends Person{ // 继承此类 @Override public String getinfo(){ // 覆写方法 return "这是一个Student类。" ; } }; public class OverrideAnnotationDemo01{ public static void main(String args[]){ Person per = new Student() ; System.out.println(per.getInfo()) ; // 输出信息 } }; |
使用Override注释可以保证程序正确的执行。
16-1-2、@Deprecated
使用Deprecated注释的Annotation本身是不建议使用的一个操作。
class Demo{ @Deprecated // 声明不建议使用的操作 public String getInfo(){ return "这是一个Person类。" ; } }; public class DeprecatedAnnotationDemo01{ public static void main(String args[]){ Demo d = new Demo() ; System.out.println(d.getInfo()) ; } }; |
以上程序编译出错,而是出现了一个安全的警告信息。
@Deprecated // 声明不建议使用的操作 class Demo{ public String getInfo(){ return "这是一个Person类。" ; } }; public class DeprecatedAnnotationDemo02{ public static void main(String args[]){ Demo d = new Demo() ; System.out.println(d.getInfo()) ; } }; |
16-1-3、@SuppressWarnings
用于压制警告信息。
以之前的泛型操作为例,在泛型中如果没有指定泛型类型,则使用时肯定出现安全警告。
class Demo<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } }; public class SuppressWarningsAnnotationDemo01{ public static void main(String args[]){ Demo d = new Demo() ; d.setVar("李兴华") ; System.out.println("内容:" + d.getVar()) ; } }; |
此时就可以使用SuppressWarnings这个Annotation将这种警告信息进行压制。
class Demo<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } }; public class SuppressWarningsAnnotationDemo01{ @SuppressWarnings(“unchecked”) public static void main(String args[]){ Demo d = new Demo() ; d.setVar("李兴华") ; System.out.println("内容:" + d.getVar()) ; } }; |
以上只是压制了一个警告信息,当然,也可以同时压制多个警告信息,只需要以数组的形式出现即可。
@Deprecated class Demo<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } }; public class SuppressWarningsAnnotationDemo01{ @SuppressWarnings(“unchecked”,”deprecation”) public static void main(String args[]){ Demo d = new Demo() ; d.setVar("李兴华") ; System.out.println("内容:" + d.getVar()) ; } }; |
@SuppressWarnings中的关键字
NO | 关键字 | 描述 |
1 | deprecation | 使用了不赞成使用的类或方法时的警告 |
2 | unchecked | 执行了未检查的转换时警告,例如:泛型操作中没有指定泛型类型 |
3 | fallthrough | 当switch程序块直接通往下种情况而没有Break时的警告 |
4 | path | 在类路径、源文件路径等中有不存在的路径时警告 |
5 | serial | 当在可序列化的类上缺少serialVersionUID定义时的警告 |
6 | finally | 任何finally子句不能正常完成时的警告 |
7 | all | 关于以上所有情况的警告 |
在设置注释信息的时候,是以keyvalue的形式出现的,所以以上的@SuppressWarnings也可以直接使用“value={“unchecked”,”deprecation”}”的方式设置。
@Deprecated class Demo<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } }; public class SuppressWarningsAnnotationDemo01{ @SuppressWarnings(value={“unchecked”,”deprecation”}) public static void main(String args[]){ Demo d = new Demo() ; d.setVar("李兴华") ; System.out.println("内容:" + d.getVar()) ; } }; |
16-2、Annotation——自定义Annotation
Annotation定义格式:
·[public] @interface Annotation名称{
数据类型 变量名称();
}
定义一个简单的Annotation:
public @interface MyDefaultAnnotationNoneParm{ } |
之后就可以直接在程序中使用“@Annotation名称”的格式。
@MyDefaultAnnotationNoneParm class Demo{ }; |
此时就表示在Demo类上使用Annotation。
还可以向Annotation中设置,使用变量接收参数:
public @interface MyDefaultAnnotationSingleParam{ public String value(); //接收设置的内容 } |
在使用的时候就必须清楚的指明变量的内容:
@MyDefaultAnnotationSingleParam(“cyg”) class Demo{ }; |
或者也可以使用明确的标记,表示内容赋给哪个参数:
@MyDefaultAnnotationSingleParam(value=“cyg”) class Demo{ }; |
以上的参数是要赋给value属性的。
既然可以设置一个参数,则也就可以同时设置多个参数:
public @interface MyDefaultAnnotationSingleParam{ public String key(); public String value(); //接收设置的内容 } |
此Annotation在使用的时候需要设置两个参数,一个是key,另外一个是value。
@MyDefaultAnnotationMoreParam(key=”MLDN”,value=“cyg”) class Demo{ }; |
也可以设置一个数组进去:
public @interface MyDefaultAnnotationArrayParam{ public String[] value(); //接收设置的内容 } |
接收的内容本身是一个数组类型,要传递数组,类似与之前的SuppressWarnings
@MyDefaultAnnotationArrayParam(value={”MLDN”, “cyg”}) class Demo{ }; |
以上所定义的全部的Annotation中有一个特点:所有的参数内容需要在使用注释的时候设置上去,那么也可以为一个参数设置默认的内容,在声明的时候使用default即可。
public @interface MyDefaultAnnotationValue{ public String key() default “MLDN”;//指定好了默认值 public String value() default “cyg”; //指定好了默认值 } |
当在去使用此Annotation的时候就可以不用设置内容。
@MyDefaultAnnotationValue class Demo{ } |
没有设置内容,编译也不会出现任何的错误。
在操作中,对于一个Annotation而言有时候会固定其取值范围,只能取固定的几个值,那么这个时候实际上就需要依靠枚举。
public enum MyName{ MLDN,cyg,chen; } |
以后的Annotation的取值,只能从这三个值中取走。
public@interface MyDefaultAnnotationEnum{ public MyName name() default MyName.cyg; //指定默认值 } |
此时以上的Annotation已经设置好了一个枚举中的内容作为默认值,那么外部使用此Annotation的时候也需要从枚举固定取值:
@MyDefaultAnnotationEnum(name=MyName.cyg) //只能从固定的枚举中取内容 class Demo{ } |
Retention和RetentionPolicy
在Annotation可以使用Retention定义一个Annotation的保存范围,此Annotation的定义如下:
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Retention{ RetentionPolicy value(); } |
在以上的Retention定义中存在了一个RetentionPolicy的变量,此变量用于指定Annotation的保存范围,RetentionPolicy包含三种范围:
NO | 范围 | 描述 |
1 | SOURCE | 此Annotation类型的信息只会保留在程序源文件之中(*.java),编译之后不会保存在编译好的类文件(*.class)之中 |
2 | CLASS | 此Annotation类型将保留在程序源文件(*.java)和编译之后的类文件(*.class)之中,在使用此类的时候,这些Annotation信息将不会被加载到虚拟机(JVM)之中,如果一个Annotation声明时没有指定范围,则默认是此范围 |
3 | RUNTIME | 此Annotation类型的信息保留在源文件(*.java)、类文件(*.class)在执行时也会加载到JVM中 |
在三个范围中,最需要的关心的就是RUNTIME范围,因为在执行的时候起作用。
使用Retention指定一个Annotation的范围,范围为RUNTIME范围:
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(value=RetentionPolicy.RUNTIME) //表示此Annotation在运行时有效 public @interface MyDefaultRetentionAnnotation{ public String name() default “cyg”; } |
此Annotation可以在运行时起作用,而且在反射与Annotation的操作中,也必须使用此种范围。
内建Annotation的RetentionPolicy
三个内建的Annotation的定义:
·Override定义采用的是@Retention(value=SOURCE),只能在源文件中出现。
·Deprecated定义采用的是@Retention(value=RUNTIME),可以在执行时出现。
·SuppressWarnings定义采用的是@Retention(value=SOURCE),只能在源文件中出现。
16-3、Annotation——反射与Annotation
一个Annotation如果要想让其变得有意义,则必须结合反射机制取得Annotation中设置的全部内容。
通过反射取得Annotation
在Class类中存在以下几种与Annotation操作有关的方法:
NO | 方法 | 类型 | 描述 |
1 | public <A extends Annotation> A getAnnotation(Class<A> annotationClass) | 普通 | 如果在一个元素中存在注释,则取得全部注释 |
2 | public Annotation[] getAnnotations() | 普通 | 返回此元素上的所有注释 |
3 | public Annotation[] getDeclaredAnnotations() | 普通 | 返回直接存放在此元素上的所有注释 |
4 | public boolean isAnnotation() | 普通 | 判断元素是否表示一个注释 |
5 | public boolean isAnnotationPresent(Class<? Extends Annotation> annotationClass) | 普通 | 判断一个元素上是否存在注释 |
例:
package org.lxh.demo16.reflectannotation ; public class SimpleBeanOne{ @SuppressWarnings("unchecked") @Deprecated @Override public String toString(){ return "Hello LiXingHua!!!" ; } }; |
同时设置了三个Annotation,那么此时注意,只有Depreacted的Annotation的定义范围是RUNTIME范围,所以此时通过反射的话只能取得一个。
import java.lang.annotation.Annotation ; import java.lang.reflect.Method ; public class ReflectDemo01{ public static void main(String args[]) throws Exception{ // 所有异常抛出 Class <?> c = null ; c = Class.forName("org.lxh.demo16.reflectannotation.SimpleBeanOne") ; Method toM = c.getMethod("toString") ; // 找到toString()方法 Annotation an[] = toM.getAnnotations() ; // 取得全部的Annotation for(Annotation a:an){ // 使用 foreach输出 System.out.println(a) ; } } }; |
此时,已经取得了一个Annotation。
以上的操作代码实际上是通过三个系统内建的Annotation完成的,那么也可以自定义一个Annotation。
package org.lxh.demo16.reflectannotation ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; @Retention(value=RetentionPolicy.RUNTIME) // 此Annotation在类执行时依然有效 public @interface MyDefaultAnnotationReflect{ public String key() default "LXH" ; public String value() default "李兴华" ; } |
以上的Annotation范围是在运行时依然有效,下面定义一个类使用此Annotation。
package org.lxh.demo16.reflectannotation ; public class SimpleBeanTwo{ @SuppressWarnings("unchecked") @Deprecated @Override @MyDefaultAnnotationReflect(key="MLDN",value="www.mldnjava.cn") public String toString(){ return "Hello LiXingHua!!!" ; } }; |
下面使用反射取得指定的Annotation,因为现在唯一设置内容的就是MyDefaultAnnotationRelfect.
import org.lxh.demo16.reflectannotation.MyDefaultAnnotationReflect ; import java.lang.annotation.Annotation ; import java.lang.reflect.Method ; public class ReflectDemo02{ public static void main(String args[]) throws Exception{ // 所有异常抛出 Class <?> c = null ; c = Class.forName("org.lxh.demo16.reflectannotation.SimpleBeanTwo") ; Method toM = c.getMethod("toString") ; // 找到toString()方法 if(toM.isAnnotationPresent(MyDefaultAnnotationReflect.class)){ // 判断是否是指定的Annotation MyDefaultAnnotationReflect mda = null ; mda = toM.getAnnotation(MyDefaultAnnotationReflect.class) ; // 得到指定的Annotation String key = mda.key() ; // 取出设置的key String value = mda.value() ; // 取出设置的value System.out.println("key = " + key) ; System.out.println("value = " + value) ; } } }; |
总结:
1、Annotation在实际的开发中,不管如何使用,其最终肯定是结合反射机制,也就是说可以通过Annotation设置一些内容到一个方法上去,以完成特定的功能。
2、在EJB3.0中可以发现有更多的Annotation应用。
16-4、Annotation——深入Annotation
之前定义的Annotation,如果没有明确的说明可以在任意的位置上使用。
@MyDefaultAnntationReflect(key="MLDN",value="www.mldnjava.cn") public class SimpleBean{ @MyDefaultAnntationReflect(key="MLDN",value="www.mldnjava.cn") public String toString(){ return "Hello LiXingHua!!!" ; } }; |
如果现在需要指定其使用的范围,则必须使用@Target注释:
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION TYPE) public @interface Target |
ElementType的保存范围
NO | 范围 | 描述 |
1 | public static final ElementType ANNOTATION_TYPE | 只能用在注释声明上 |
2 | public static final ElementType CONSTRUCTOR | 只能用在构造方法声明上 |
3 | public static final ElementType FIELD | 只能用在字段声明(包括枚举常量)上 |
4 | public static final ElementType LOCAL_VARLABLE | 只能用在局部变量声明上 |
5 | pubic static final ElementType METHOD | 只能用在方法的声明上 |
6 | public static final ElementType PACKAGE | 只能用在包的声明上 |
7 | public static final ElementType PARAMETER | 只能用在参数的声明上 |
8 | public static final ElementType TYPE | 只能用在类、接口、枚举类型上 |
现在定义一个Annotation,只能在类上使用,类型是TYPE:
import java.lang.annotation.Target ; import java.lang.annotation.ElementType ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; @Target(ElementType.TYPE) // 此注释只能用在类上 @Retention(value=RetentionPolicy.RUNTIME) public @interface MyTargetAnntation{ public String key() default "LXH" ; public String value() default "李兴华" ; } |
此时在SimpleBean的类及方法的声明上使用此Annotation:
@MyTargetAnntation(key="MLDN",value="www.mldnjava.cn") public class SimpleBean{ @MyTargetAnntation(key="MLDN",value="www.mldnjava.cn") public String toString(){ return "Hello LiXingHua!!!" ; } }; |
如果现在希望一个Annotation可以在类及方法上同时使用,则必须设置多个范围:
import java.lang.annotation.Target ; import java.lang.annotation.ElementType ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; @Target({ElementType.TYPE,ElementType.METHOD}) // 此注释只能用在类上 @Retention(value=RetentionPolicy.RUNTIME) public @interface MyTargetAnntation{ public String key() default "LXH" ; public String value() default "李兴华" ; } |
@Documented,可以用在任何Annotation上使用。所有的Annotation默认情况下都是使用@Documented进行注释的,而且在生成javadoc的时候可以通过@Documented设置一些说明信息。
import java.lang.annotation.Documented ; @Documented public @interface MyDocumentedAnntation{ public String key() default "LXH" ; public String value() default "李兴华" ; } |
成功之后,在使用此Annotation的时候就可以增加一些信息上去。
@MyDocumentedAnntation(key="MLDN",value="www.mldnjava.cn") public class SimpleBeanDocumented{ /** * 此方法在对象输出时调用,返回对象信息 */ @MyDocumentedAnntation(key="MLDN",value="www.mldnjava.cn") public String toString(){ return "Hello LiXingHua!!!" ; } }; |
之后通过javadoc命令,生成java doc文档。
F:\网页\李兴华\031604_【第16章:Annotation】_深入Annotation\代码>javadoc -d doc SimpleBeanDocumented.java 正在加载源文件SimpleBeanDocumented.java... 正在构造 Javadoc 信息... 标准 Doclet 版本 1.7.0_01 正在构建所有程序包和类的树... 正在生成doc\SimpleBeanDocumented.html... 正在生成doc\package-frame.html... 正在生成doc\package-summary.html... 正在生成doc\package-tree.html... 正在生成doc\constant-values.html... 正在构建所有程序包和类的索引... 正在生成doc\overview-tree.html... 正在生成doc\index-all.html... 正在生成doc\deprecated-list.html... 正在构建所有类的索引... 正在生成doc\allclasses-frame.html... 正在生成doc\allclasses-noframe.html... 正在生成doc\index.html... 正在生成doc\help-doc.html... |
@Inherited注释,此注释表示一个Annotation是否可以被继承下来。
package org.lxh.demo16.inheriteddemo ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; import java.lang.annotation.Documented ; import java.lang.annotation.Inherited ; @Documented @Inherited @Retention(value=RetentionPolicy.RUNTIME) public @interface MyInheritedAnnotation{ public String name() ; } |
定义一个父类,在父类上使用此Annotation:
package org.lxh.demo16.inheriteddemo ; @MyInheritedAnnotation(name=”cyg”) public class Person{ } |
定义子类:
public class Student extends Person{ } |
按照所解释的,使用Inherited声明的Annotation是可以被子类继承下来的。
import java.lang.annotation.Annotation ; import org.lxh.demo16.inheriteddemo.MyInheritedAnnotation ; public class ReflectInheritedDemo{ public static void main(String args[]) throws Exception{ Class<?> c = null ; c = Class.forName("org.lxh.demo16.inheriteddemo.Student") ; Annotation ann[] = c.getAnnotations() ; // 取得全部的Annotation for(Annotation a:ann){ // 输出 System.out.println(a) ; } // 继续取得此Annotation设置的内容 if(c.isAnnotationPresent(MyInheritedAnnotation.class)){ MyInheritedAnnotation mda = null ; mda = c.getAnnotation(MyInheritedAnnotation.class) ; String name = mda.name() ; // 取出name的内容 System.out.println("name = " + name) ; } } } |
总结:
·熟悉Documented注释的作用:加入说明信息。
·熟悉Target的作用,并使用Target注释指定注释的使用位置。
·如果一个Annotation要想被子类继承下来,则使用Inherited注释说明。
·反射机制对于操作Annotation是最重要的。
猜你喜欢
- 2024-10-19 Java 项目编译提示 javax.xml.bind.annotation does not exist 错误
- 2024-10-19 Android annotation包下常用的注解
- 2024-10-19 SpringMVC疑难一:mvc:annotation-dr
- 2024-10-19 Spring 中 AnnotationConfigUtils
- 2024-10-19 spring mvc 配置失效了?(springmvc的配置)
- 2024-10-19 为什么都爱着江南?黛瓦白墙,烟雨朦胧,是文人魂牵梦绕的故乡
- 2024-10-19 Spring框架系列之构造方法底层剖析01
- 2024-10-19 基于.NET6包含DDD,ES,CQRS等概念的开源
- 2024-10-19 spring 中 AnnotationUtils 的常用方法
- 2024-10-19 SpringBoot实战4-Spring基础-IoC容器
你 发表评论:
欢迎- 最近发表
-
- Win11学院:如何在Windows 11上使用WSL安装Ubuntu
- linux移植(Linux移植freemodbus)
- 独家解读:Win10预览版9879为何无法识别硬盘
- 基于Linux系统的本地Yum源搭建与配置(ISO方式、RPM方式)
- Docker镜像瘦身(docker 减小镜像大小)
- 在linux上安装ollama(linux安装locale)
- 渗透测试系统Kali推出Docker镜像(kali linux渗透测试技术详解pdf)
- Linux环境中部署Harbor私有镜像仓库
- linux之间传文件命令之Rsync傻瓜式教程
- 解决ollama在linux中安装或升级时,通过国内镜像缩短安装时长
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)