Java内置系统注解和元注解
来源:互联网 发布:工业数据采集难点 编辑:程序博客网 时间:2024/04/29 21:37
第一节:注解(Annotation)的作用
Annotation(注解)是JDK5.0及以后版本引入的。它的作用是修饰程序元素。什么是程序元素呢?例如:包、类、构造方法、方法、成员变量等。
注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的。
java提供了一套机制,使得我们可以对方法、类、参数、包、域以及变量等添加标注(即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用。
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记。程序可以利用java的反射机制来了解你的类及各种元素上有无何种标记,针对不同的标记,就去做相应的事件。
第二节:定义注解
定义新的Annotation类型使用@interface关键字(在原有interface关键字前增加@符号)。定义一个新的Annotation类型与定义一个接口很像,例如:
public @interface Test{}
定义完该Annotation后,就可以在程序中使用该Annotation。使用Annotation,非常类似于public、final这样的修饰符,通常,会把Annotation另放一行,并且放在所有修饰符之前。例如:
@Testpublic 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就是用来指定某个接口必须是函数式接口,否则就会编译出错。
@FunctionalInterface
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的说明。
示例:
@Documentedpublic @interface Testable {}
public class Test {@Testablepublic 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)@Inheritedpublic @interface MyTag{}
package com.demo2;@MyTagpublic 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注解的源码,
源码分析如下:
第一:元注解@Retention,成员value的值为RetentionPolicy.RUNTIME。
第二:元注解@Target,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
第三:成员名称为value,类型为ElementType[]
另外,需要注意一下,如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
第六节:注解的底层实现
定义一个注解:
分析其字节码,如下图所示:
C:\Users\Administrator\workspace\cache\bin>javap -verbose Cache
分析上面的字节码,我们可以得出:
第一:
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自定义注解中讲解》 。
- Java内置系统注解和元注解
- Java_注解 (元注解 / Java内置注解 / Android内置注解)
- Java注解[内置系统注解与Spring中常见注解]
- Java自定义注解和元注解
- java元注解和自定义注解
- 【注解】01.java元注解
- java元注解和自定义注解---超易懂
- 深入浅出Java Annotation(元注解和自定义注解)
- java元注解和自定义注解的使用方法
- java中的元注解
- JAVA 的元注解
- Java元注解
- Java元注解
- java中的元注解
- JAVA的元注解。
- java 元注解
- java元注解
- java元注解
- [C++] 模板类实现简单链表
- forward和redirect对比
- 数据结构实验之排序六:希尔排序
- centos7 安装openvpn 缺少route组件
- NYOJ 608 畅通工程
- Java内置系统注解和元注解
- C语言一些巧妙method
- LeetCode:382. Linked List Random Node(蓄水池抽样算法C++)
- 3.8 poll函数的详细分析
- Socket以及Socket Php实例
- Java IO LineNumberReader
- TextSwitch 和 ImageSwitch源码分析
- fragment倒包问题
- java设计模式进阶_flyweight