Java内置系统注解和元注解
2016-08-23 16:18
330 查看
第一节:注解(Annotation)的作用
Annotation(注解)是JDK5.0及以后版本引入的。它的作用是修饰程序元素。什么是程序元素呢?例如:包、类、构造方法、方法、成员变量等。注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的。
java提供了一套机制,使得我们可以对方法、类、参数、包、域以及变量等添加标注(即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用。
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记。程序可以利用java的反射机制来了解你的类及各种元素上有无何种标记,针对不同的标记,就去做相应的事件。
第二节:定义注解
定义新的Annotation类型使用@interface关键字(在原有interface关键字前增加@符号)。定义一个新的Annotation类型与定义一个接口很像,例如:
public @interface Test{ }
定义完该Annotation后,就可以在程序中使用该Annotation。使用Annotation,非常类似于public、final这样的修饰符,通常,会把Annotation另放一行,并且放在所有修饰符之前。例如:
@Test public class MyClass{ .... }
根据注解是否包含成员变量,可以把注解分为如下两类:
标记注解:没有成员变量的Annotation被称为标记。这种Annotation仅用自身的存在与否来为我们提供信息,例如@override等。
元数据注解:包含成员变量的Annotation。因为它们可以接受更多的元数据,因此被称为元数据Annotation。 成员以无参数的方法的形式被声明,其方法名和返回值定义了该成员变量的名字和类型。
成员变量
Annotation只有成员变量,没有方法。Annotation的成员变量在Annotation定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。例如:
public @interface MyTag{ string name(); int age(); }
示例中定义了2个成员变量,这2个成员变量以方法的形式来定义。
一旦在Annotation里定义了成员变量后,使用该Annotation时就应该为该Annotation的成员变量指定值。例如:
public class Test{ @MyTag(name="红薯",age=30) public void info(){ ...... } }
也可以在定义Annotation的成员变量时,为其指定默认值,指定成员变量默认值使用default关键字。示例:
public @interface MyTag{ string name() default "我兰"; int age() default 18; }
如果Annotation的成员变量已经指定了默认值,使用该Annotation时可以不为这些成员变量指定值,而是直接使用默认值。例如:
public class Test{ @MyTag public void info(){ ...... } }
如果注解只有一个成员变量,则建议取名为value,在使用时可用忽略成员名和赋值符=
第三节:基本注解
在java.lang包下,JAVA提供了5个基本注解::
@Override
限定重写父类方法。对于子类中被@Override 修饰的方法,如果存在对应的被重写的父类方法,则正确;如果不存在,则报错。@Override 只能作用于方法,不能作用于其他程序元素。
@Deprecated
用于表示某个程序元素(类、方法等)已过时。如果使用了被@Deprecated修饰的类或方法等,编译器会发出警告。
@SuppressWarnings
抑制编译器警告。指示被@SuppressWarnings修饰的程序元素(以及该程序元素中的所有子元素,例如类以及该类中的方法.....)取消显示指定的编译器警告。例如,常见的@SuppressWarnings(value="unchecked")
SuppressWarnings注解的常见参数值的简单说明:
1.deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
4.path:在类路径、源文件路径等中有不存在的路径时的警告;
5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
6.finally:任何 finally 子句不能正常完成时的警告;
7.all:关于以上所有情况的警告。
@SafeVarargs
@SafeVarargs是JDK 7 专门为抑制“堆污染”警告提供的。
@FunctionalIterface (java 8 新增的)
函数式接口。Java8规定:如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。
@FunctionalInterface就是用来指定某个接口必须是函数式接口,否则就会编译出错。
[b] @FunctionalInterface[/b]
public interface Fun
{
static void foo()
{
System.out.println("foo类方法");
}
default void bar()
{
System.out.println("bar默认方法");
}
void test();//只定义了一个抽象方法
}
如在上面的接口中再加一个抽象方法abc(),则会编译出错。
第四节 元注解
在java.lang.annotation包下,定义了6个元注解。元注解就是修饰注解的注解。
拿到一个注解,如何知道它是否是元注解呢?需要看它的元注解(无论是元注解还是普通注解都是有元注解的),如果看到这样的元注解:@Target(ElementType.ANNOTATION_TYPE),那么此时这个注解一定是元注解。
@Retention
@Target
@Documented
@Inherited
@Repeatable (java 8新增)
类型注解
@Repetable和类型注解在另外一篇博文中介绍。
4.1 @Retention
@Retention用于指定注解可以保留多长时间(生命周期)。
@Retention包含一个名为“value”的成员变量,该value成员变量是RetentionPolicy枚举类型。使用@Retention时,必须为其value指定值。value成员变量的值只能是如下3个:
RetentionPolicy.SOURCE:Annotation只保留在源代码中,编译器编译时,直接丢弃这种Annotation,不记录在.class文件中。
RetentionPolicy.CLASS:编译器把Annotation记录在class文件中。当运行Java程序时,JVM中不可获取该Annotation信息。这是默认值
RetentionPolicy.RUNTIME:编译器把Annotation记录在class文件中。当运行Java程序时,JVM可获取该Annotation信息,程序可以通过反射获取该Annotation的信息。
示例:
package com.demo1; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; //name=value形式 //@Retention(value=RetentionPolicy.RUNTIME) //直接指定 @Retention(RetentionPolicy.RUNTIME) public @interface MyTag{ String name() default "我兰"; }
如果Annotation里有一个名为“value“的成员变量,使用该Annotation时,可以直接使用XXX(val)形式为value成员变量赋值,无须使用name=val形式。
4.2 @Target
@Target指定Annotation用于修饰哪些程序元素。@Target也包含一个名为”value“的成员变量,该value成员变量类型为ElementType[ ],ElementType为枚举类型,值有如下几个:
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包
示例1(单个ElementType):
package com.demo1; import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target(ElementType.FIELD) public @interface AnnTest { String name() default "sunchp"; }
示例2(多个ElementType):
package com.demo1; import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ ElementType.FIELD, ElementType.METHOD }) public @interface AnnTest { String name() default "sunchp"; }
4.3 @Documented
如果定义注解A时,使用了@Documented修饰定义,则在用javadoc命令生成API文档后,所有使用注解A修饰的程序元素,将会包含注解A的说明。
示例:
@Documented public @interface Testable { }
public class Test { @Testable public void info() { } }
4.4 @Inherited
@Inherited指定注解具有继承性。如果某个类使用了@xxx注解(定义该注解时使用了@Inherited修饰)修饰,则其子类将自动被@xxx修饰
示例:
package com.demo2; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface MyTag{ }
package com.demo2; @MyTag public class Base { }
package com.demo2; //SubClass只是继承了Base类 //并未直接使用@MyTag注解修饰 public class SubClass extends Base { public static void main(String[] args) { System.out.println(SubClass.class.isAnnotationPresent(MyTag.class)); } }
示例中Base使用@MyTag修饰,SubClass继承Base,而且没有直接使用@MyTag修饰,但是因为MyTag定义时,使用了@Inherited修饰,具有了继承性,所以运行结果为true。
如果MyTag注解没有被@Inherited修饰,则运行结果为:false。
第五节:注解的语法与定义形式
(1)以@interface关键字定义
(2)注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
上面的语法不容易理解,下面通过例子来说明一下,这个例子就是Target注解的源码,
1 2 3 4 5 6 | @Retention(value=RetentionPolicy.RUNTIME) @Target(value={ElementType.ANNOTATION_TYPE}) public@interfaceTarget { ElementType[]value(); } |
第一:元注解@Retention,成员value的值为RetentionPolicy.RUNTIME。
第二:元注解@Target,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
第三:成员名称为value,类型为ElementType[]
另外,需要注意一下,如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
第六节:注解的底层实现
定义一个注解:1 2 3 4 5 6 | @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public@interfaceCache { Stringvalue()default"cache"; } |
C:\Users\Administrator\workspace\cache\bin>javap -verbose Cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | Classfile/C:/Users/Administrator/workspace/cache/bin/Cache.class Last modified2016-7-23;size429bytes MD5checksum771f9c4d63ce2ded5d3b093deebd2c69 Compiled from"Cache.java" publicinterfaceCacheextendsjava.lang.annotation.Annotation minor version:0 majorversion:52 flags:ACC_PUBLIC,ACC_INTERFACE,ACC_ABSTRACT,ACC_ANNOTATION Constantpool: #1 = Class #2 // Cache #2 = Utf8 Cache #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Class #6 // java/lang/annotation/Annotation #6 = Utf8 java/lang/annotation/Annotation #7 = Utf8 value #8 = Utf8 ()Ljava/lang/String; #9 = Utf8 AnnotationDefault #10 = Utf8 cache #11 = Utf8 SourceFile #12 = Utf8 Cache.java #13 = Utf8 RuntimeVisibleAnnotations #14 = Utf8 Ljava/lang/annotation/Retention; #15 = Utf8 Ljava/lang/annotation/RetentionPolicy; #16 = Utf8 RUNTIME #17 = Utf8 Ljava/lang/annotation/Target; #18 = Utf8 Ljava/lang/annotation/ElementType; #19 = Utf8 TYPE { publicabstractjava.lang.Stringvalue(); descriptor:()Ljava/lang/String; flags:ACC_PUBLIC,ACC_ABSTRACT AnnotationDefault: default_value:s#10 } SourceFile:"Cache.java" RuntimeVisibleAnnotations: 0:#14(#7=e#15.#16) 1:#17(#7=[e#18.#19]) |
第一:
public interface Cache extends java.lang.annotation.Annotation,说明Cache注解是继承自Annotation,仍然是interface。
第二:
public abstract java.lang.String value(),说明value方法是abstract类型。
当开发者使用了注解修饰了类、方法、成员变量等成员之后,这些注解不会自己生效,必须由开发者提供相应的代码来提取并处理注解信息。这些提取和处理注解的代码统称为APT(Annotation Processing Tool)注解处理工具。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。这一部分在《Java自定义注解中讲解》 。
相关文章推荐
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 利用Spring AOP与JAVA注解为系统增加日志功能
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 系列文章:在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 为Android系统内置Java应用程序测试Application Frameworks层的硬件服务接口
- (六)在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- Java内置三种注解
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 17---java中Annotation01(系统内置的)
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务