
本文共 3882 字,大约阅读时间需要 12 分钟。
前言
要想理解Annotation的作用,就必须先得知道何为元数据。元数据就是关于数据的数据,是添加到程序元素诸如方法、字段、类和包上的额外信息。
注解Annotation就是Java平台的元数据,该机制允许在代码中添加自定义注释,并允许通过反射,以编程方式访问元数据注释。通过为类、方法等提供附加额外数据的标准方法,元数据功能具有简化和改进的潜在能力。Annotation作用
注解的作用,就是元数据的作用。需要注意的是,Annotation不影响程序代码的执行。无论是增加、删除Annotation,代码执行都不会受到影响。
内建注解
Java提供了几种内建的注解,如@Override、@Deprecated、@SuppressWarnings以及@FunctionalInterface。内建注解主要体现了元数据的编译检查作用。
1.@Override
告知编译器,我们要重写超类的当前方法。如果某方法带有该注解,但并没有重写父类的相应方法,会报错。如果父类没有这个重写方法,也会报错。@Override可适用的元素为方法,仅仅保留在java源文件中。
2.@Deprecated
告知编译器,该方法已经过时了。
public class Person { @Deprecated public void info(){ }}
这里再调用info方法,就提示过时了。
Person person = new Person(); person.info();
3.@SuppressWarnings
告知编译器忽略特定的警告信息,比如在泛型中使用原生数据类型就会发出警告,使用该注解后警告不再发出。可适用于除注解类型声明和包名之外的所有元素,仅仅保留在java源文件中。
此注解有value()方法,支持用户设置多个字符串参数来忽略警告。如@SuppressWarnings(value={“deprecation”,“uncheck”})4.@FunctionalInterface
告知编译器,检查这个接口。保证该接口只能有一个抽象方法,否则编译出错。
元Annotation
java.lang.annotation包提供了6个元Annotation,其中有5个用于修饰其他Annotation定义。
自定义Annotation:当一个接口直接继承java.lang.annotation.Annotation时,依然还是接口而非注解。只能通过@interface关键字的方式,隐含的继承.Annotation。1.@Documented
用户指定被其修饰的Annotation将会被javadoc工具提取为文档,如果定义Annotation类使用了@Documented修饰,所有使用其修饰的API文档中将包含该Annotation说明
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(value = { CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})public @interface Deprecated { }
定义@Deprecated的时候使用了@Documented,任何元素使用@Deprecated修饰再生成API文档时,将会包含@Deprecated的说明
@Deprecatedpublic String(byte[] ascii,int hibyte,int offset,int count)
该注解实现了编写文档功能。
2.@Inherited
被他修饰的Annotation就会具有继承性,如果父类被注解,子类将会被其修饰
3.@retention
表示该注解类型的注解保留的时长,当注解类型声明中没有@retention元注解,则默认保留策略为RetentionPolcy.CLASS,保留策略是枚举类型,共有3种。
a.SOURCE仅存在Java源文件,经过编译器后就丢弃相应的注解 b.CLASS存在java源文件,以及经编译器生成的class字节码文件。但在运行时JVM不再保留 c.RUNTIME存在源文件、class字节码文件,以及保留在运行时JVM中,可通过反射读取注解4.@Target
表示该注解类型的所适用的程序元素的类型,无该注解可默认为适用所有元素类型,否则强制实施相应适用限制。程序元素是枚举类型,分为8种:
ANNOTATION_TYPE(注解类型说明)、CONSTURCTOR(构造方法声明)、FIELD(字段声明)、LOCAL_VARIABLE(局部变量声明)、METHOD(方法声明)、PACKAGE(包声明)、PARAMETER(参数声明)、TYPE(类、接口或枚举声明)自定义注解
创建自定义注解,和创建接口相似,需要以@开头。
@Documented@Target(ElementType.METHOD)@Inherited@Retention(RetentionPolicy.RUNTIME)//保留策略public @interface MyAnnotation { String name(); String website() default "hello"; int revision() default 1;}
自定义注解中定义变量的规则:以无形参的方法形式来声明,即注解方法不带参数:name() website();注解方法返回值类型:基本类型、String、Enums、Annotation以及前面这些数组类型;注解方法可有默认值:default “hello” 默认website=“hello”;
当然注解中也可以不存在成员变量,再使用解析注解进行操作时,仅以是否包含该注解来进行操作。当注解中有成员变量时,若没有默认值,需在使用注解时指明成员变量的值。public class AnnotationDemo { @MyAnnotation(name = "husky",website = "hello",revision = 1) public static void main(String [] args){ System.out.println("我是主方法"); } @SuppressWarnings({ "deprecation","uncheck"}) @MyAnnotation(name = "husky",website = "hello",revision = 2) public void demo(){ System.out.println("我是demo"); }}
由于设定了保留策略为RetentionPolicy.RUNTIME,可以在运行时通过反射来使用,否则无法通过反射机制来获取。
注解解析
反射位于java.lang.reflect,其中有一个接口为AnnotatedElement。该接口主要有5个实现类:Class、Consturctor、Field、Method、Package。此外,还定义了几个注释相关的核心方法:

public class AnnotationParser { public static void main(String [] args) throws SecurityException,ClassNotFoundException{ String clazz = "com.example.husky.mergesort.Documented.AnnotationDemo"; Method[] demoMethod = AnnotationParser.class.getClassLoader().loadClass(clazz).getMethods(); for (Method method: demoMethod){ if (method.isAnnotationPresent(MyAnnotation.class)){ MyAnnotation annotationInfo = method.getAnnotation(MyAnnotation.class); System.out.println("method:"+method); System.out.println("name"+annotationInfo.name()+",website:"+ annotationInfo.website()+",revision:"+annotationInfo.revision()); } } }}
发表评论
最新留言
关于作者
