注解
1、注解的概念
j2se 提供了很多新特性。其中一个很重要的特性就是对元数据(Metadata)的支持。在j2se 5.0 中,这种数据被称为注释(Annontation).通过使用注释,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充的信息。Annontation 可以用来修饰类、属性、方法,而且Annontation 不影响程序运行,无论是否使用Annontation 代码都可以正常运行。
2、注解的定义方法以及原理
定义方法:使用注解就是在其前面加上@符号,并把该注解当成一个修饰符使用,可以修饰程序中的元素主机的原理:Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。
annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。
Java语言解释器在工作时会忽略这些annotation,因此在JVM中这些annotation是“不起作用”的,只能通过配套的工具才能对这些annontaion类型的信息进行访问和处理。
Annotation与interface的异同:
1)、Annotation类型使用关键字@interface而不是interface。
这个关键字声明隐含了一个信息:它是继承了java.lang.annotation.Annotation接口,并非声明了一个interface
2)、Annotation类型、方法定义是独特的、受限制的。
Annotation类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用default和一个默认数值来声明成员的默认值,null不能作为成员默认值,这与我们在非annotation类型中定义方法有很大不同。
Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。
3)、Annotation类型又与接口有着近似之处。
它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。
3、三个基本的注解
(1)Override 就是用来限定方法重载的,它强制一个子类去复写父类的方法。@Override
public boolean equals(Object obj)//此处的Object写成其他类型的就会报错
{
return false;
}
此简单的注解为我们的程序解决了大麻烦,为程序的排错减少了不必要的麻烦
(2)Deprecated
用于标记程序的某个元素已过时,在以后的程序应用中,编译器就会给出警告。
public static void main(String[] args) {
System.runFinalizersOnExit(true);//该方法已经过时,eclips会自动在其上面划线
}
注意:@Override 使用限制。
@Override 在使用时只能在方法上使用,而其他元素,如类、属性等上面是不可以使用的。
(3)SupressWarnings
抑制编译器警告指示被注解的程序元素取消显示的指定的编译器警告,例如我们在定义集合的时候,没有定义泛型的时候,使用了这个标记,则编译的时候就不会引起警告。
@SuppressWarnings(value="uncheck")
public static void main(String[] args) {
//System.runFinalizersOnExit(true);
List list=new ArrayList();
}
如上面的程序,如果去掉@SuppressWarnings(value="uncheck")则就会引起编译警告,为了消除警告,我们要么就是去吧泛型定义完整,要么就是必须加上@SuppressWarnings(value="uncheck")。
4、自定义注解
我们在实际的运用中,通常就是自定义一个注解--->将这个自定义注解运用到一个类上--->就是编写一个类来操作运用了注解类的信息。4.1 自定义注解
定义新的注解类型就是用@Annotation关键字来定义,如下:public @interface Test {
String name();//这为注解的属性信息
int age();
}
上面就是一个简单的注解。
4.2 将自定义的注解运用到一个类上,注解可以运用在类上、方法上、变量上等。
@Test
public class MyClass {
}
如上,就是将@Test这个注解引用在MyClass这个类上。注意:注解其实就是一个类。
4.3 提取注解的信息
必须注意的是:我们声明的注解一般分为三个阶段,即:resource、class时期、runtime。如果要获得一个类中的注解信息,必须就是要运用反射的技术,因为只有从Class对象中能获得我们所需要的信息。
package com.zyk.annon;
import java.lang.reflect.Method;
public class ReflactTest2 {
public static void main(String[] args) throws Exception {
Class<?> c = null ;
c = Class.forName("com.zsc.annon.SimpleDemo2");
Method mt = c.getMethod("toString");
if(mt.isAnnotationPresent(MyAnnotationReflact.class)){
MyAnnotationReflact mda = null ;
mda = mt.getAnnotation(MyAnnotationReflact.class);
String key = mda.key();
String value = mda.value();
System.out.println("key:"+key);
System.out.println("value:"+value);
}
}
}
以上的原理就是首先获得指定的类的Class对象,再用Class对象的isAnnotationPresent(Annotation.class);方法来判断目前的类上是否有这个注解:Annotation.class。然后再用Class对象的getAnnotation(Annotation.class);方法来获取这个注解:Annotation的实例对象----因为注解也就是一个类。
以上的原理同样能运用在方法、成员上。即---Method、Field。
5、JDK的元Annotation
JDK除了3个基本的注解之外,还有几个个元Annotation可以去修饰其他的Annotation定义5.1使用@Rention
@Rention只能用于修饰一个注释,用于指定还注释可以保留多长的时间。包含一个RentionPolicy类型的value成员变量,所以在使用@Rention必须为该value成员变量指定值。value的成员变量有一下的三个值:
RentionPolicy.CLASS:就是编译器把注解留在class文件中,在jvm运行的时候,再去掉该注解,这就是默认值。
RentionPolicy.RUNTIME:就是在jvm运行的时候该注解还是存在的,程序可以通过反射的方式来获得该注释。
RentionPolicy.SOURCE:就是注释只保留在源文件中,连编译器也过不了。
5.2 使用@Target
@Target注解也是用于修饰一个注解,他也有一个value的成员变量,该成员变量有以下的值:ElementType.ANNOTATION_TYPE:指定该Annotation只能修饰Annotation
ElementType.CONSTRUCTOR:指定该Annotation只能修饰构造函数
ElementType.FIELD:指定Annotation只能修饰成员变量
ElementType.LOCAL_VARIABLE:指定该Annotation只能修饰局部变量
ElementType.METHOD:指定该Annotation只能修饰成员方法
ElementType.PACKAGE:指定Annotation只能修饰包
ElementType.PARAMETER:指定该注释只能修饰参数
ElementType.TYPE:指定该注释可以修饰类、接口、枚举、或者注释类型。