码迷,mamicode.com
首页 > 编程语言 > 详细

Java中的Annotation (二、自定义Annotation)

时间:2015-01-20 21:48:58      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:

今天学习如何开发一个自定义的Annotation。要想使Annotation有意义,还需要借用前几天学习的反射机制。

下面就开始今天的学习吧。

 

Annotation的定义格式。它类似于新创建一个接口类文件,但为了区分,我们需要将它声明为 @interface

public @interface Annotation名称{

  数据类型 变量名称();

}

下面声明了一个Annotation

public @interface MyAnnotation {
    
}

使用这个Annotation

@MyAnnotation
public class AnnotationDemo{

    public static void main(String []args){
        
    }
}

 

注意上述Annotation没有参数,这样是没有任何意义的。要让它有意义,需要借用java的反射机制。

 

有内容的Annotation

public @interface MyAnnotation {
    public String value();
}

在定义Annotation的时候使用了参数,就必须在使用其的时候清楚的指明变量的内容。

@MyAnnotation("Annotation")
public class AnnotationDemo{
    public static void main(String []args){       
    }
}

或者明确赋给value

@MyAnnotation(value="Annotation")
public class AnnotationDemo{
    public static void main(String []args){        
    }
}

可以设置一个参数,也可以设置多个参数。

public @interface MyAnnotation {
    public String key();
    public String value();
}

在使用的时候,传入要接收的参数。

@MyAnnotation(key="key",value="Annotation")
public class AnnotationDemo{
    public static void main(String []args){        
    }
}

也可为一个参数传递多个值。

public String[] value(); 接收的时候以数组形式接收。 value={"Annotation","java"}

 

相信大家现在都跟我一样,很好奇这个自定义的Annotation里面并没有定义私有域value, public String[] value() 是一个函数,那么它是怎么接收值的呢。带着这个疑问继续学习。

 

上述Annotation都必须在使用的时候,给定参数。那么能不能设置默认参数呢,使用的时候使用默认值。答案是肯定的。

public @interface MyAnnotation {
    public String key() default "java";               //指定好了默认值
    public String[] value() default "Annotation";    //指定好了默认值
}

在操作中,有时会对Annotation中的参数固定其取值范围,只能取固定的几个值,这个时候,就需要java中的枚举。

public @interface MyAnnotation {
    public Color key() default Color.BLACK;               //指定好了默认值
    public Color[] value() default Color.BLUE;            //指定好了默认值
    
    //在外部使用Annotation的时候,也需要固定枚举中的值
    public enum Color{
        RED , BLUE , BLACK
    }
}

外部

//在外部使用Annotation的时候,也需要使用枚举中的值
@MyAnnotation(key=Color.RED)
public class AnnotationDemo{
    public static void main(String []args){        
    }
}


上述是对自定义注释的简单定义与使用。

 

在Annotation中,可以使用Retention定义一个Annotation的保存范围。

@Documented
@Retention(value=RetentionPolicy.RUNTIME)
@Target(value=ElementType.ANNOTATION_TYPE)
public @interface MyAnnotation {
    public Color key() default Color.BLACK;               //指定好了默认值
    public Color[] value() default Color.BLUE;            //指定好了默认值
    
    //在外部使用Annotation的时候,也需要固定枚举中的值
    public enum Color{
        RED , BLUE , BLACK
    }
}

1、@Documented     类和方法的Annotation缺省情况下是不出现在javadoc中的,为了加入这个性质使用@Documented

 

2、@Retention

Annotation的作用范围通过RetentionPolicy来指定,RetentionPolicy有三个范围:

RetentionPolicy.SOURCE     // 此Annotation类型的信息只会保存在程序原文件之中(*.java),编译之后不会保存在编译好的文件中(*.class)

RetentionPolicy.CLASS       //  此Annotation类型的信息会保存在程序原文件之中(*.java),编译之后会保存在编译好的文件中(*.class),但在执行的时候这些Annotation信息将不会加载到JVM虚拟机中,如果                一个Annotation没有指定范围,则默认是此范围

RetentionPolicy.RUNTIME    //顾名思义了,这些Annotation类型信息将会一直保存到执行时,加载到JVM虚拟中。

在这三个范围中,我们最需要关心的就是 RetentionPolicy.RUNTIME了,因为它会在执行的时候起作用。

那么前面文章中提到的系统内建的三种Annotation都是什么作用范围呢。

@Override                   定义的时候采用的是@Retention(value=RetentionPolicy.SOURCE)

@Deprecated               定义的时候采用的是@Retention(value=RetentionPolicy.RUNTIME)

@SuppressWarnings      定义的时候采用的是@Retention(value=RetentionPolicy.SOURCE)

3、@Target

@Target注解表明某个注解应用在哪些目标上,可选择如下范围,根据因英文名,相信大家都能看懂。

ElementType.TYPE (class, interface, enum)

ElementType.FIELD (instance variable)

ElementType.METHOD

ElementType.PARAMETER

ElementType.CONSTRUCTOR

ElementType.LOCAL_VARIABLE

ElementType.ANNOTATION_TYPE (应用于另一个注解上)

ElementType.PACKAGE

4、@Inherited

@Inherited 表明是否一个使用某个annotation的父类可以让此annotation应用于子类。

示例代码如下,定义@Inherited

import java.lang.annotation.Documented;
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;

@Documented
@Retention(value=RetentionPolicy.RUNTIME)            //必须指定为RUNTIME,否则不起作用
@Target({ElementType.TYPE,ElementType.METHOD,
    ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
    ElementType.PACKAGE})
@Inherited
public @interface MyAnnotation {
    public String key();               
    public String value();                
}

 

在Stu子类中依然可取得父类中定义的注释信息。

interface A{    
    public String sayHello();
}

@MyAnnotation(key="key",value="value")
class Per implements A{
        
    public String sayHello(){
        return "hello world";
    }
}

class Stu extends Per{
    public String sayHello(){
        return "hello world";
    }
}

public class AnnotationDemo{
    
    public static void main(String []args){        
        Class <?> c = null ;        
        c = new Stu().getClass() ;
        
        if(c.isAnnotationPresent(MyAnnotation.class)){  // 判断是否是指定的Annotation
            MyAnnotation mda = null ;
            mda = c.getAnnotation(MyAnnotation.class) ;    // 得到指定的Annotation
            String key = mda.key() ;                        // 取出设置的key
            String value = mda.value() ;                    // 取出设置的value
            System.out.println("key = " + key) ;
            System.out.println("value = " + value) ;
        }            
    }
}

 

 

 

下面就是我最关心的了,如何利用反射在运行时候获得注释信息。

 

反射与Annotation

一个Annotation要想变得有意义,就需要结合反射机制。在Class类中,有如下与Annotation相关的方法。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass)       //如果一个元素存在注释,则取得其全部注释

public Annotation[] getAnnotations()                                                               //返回此元素上的所有注释

public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)  //返回直接存放在此元素上的所有注释

public boolean isAnnotation()                              //判断元素是否表示一个注释

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)     //判断一个元素上是否存在注释

等等……

下面通过代码演示如何通过反射取得Annotation

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


interface A{
    public String sayHello();
}
class Per implements A{
    @SuppressWarnings("unchecked") 
    @Override
    @Deprecated                        //只有它在运行时有效
    public String sayHello(){
        return "hello world";
    }
}

public class AnnotationDemo{
    public static void main(String []args){        
        Class <?> c = null ;        
        c = new Per().getClass() ;
        Method toM = null;
        try {
            toM = c.getMethod("sayHello") ; // 找到sayHello()方法
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
        Annotation an[] = toM.getAnnotations() ;    // 取得全部的Annotation
        for(Annotation a:an){                        // 使用 foreach输出
            System.out.println(a) ;
        }
        
    }
}

输出结果为@java.lang.Deprecated(),这显而易见,前面已经提到了,只有@Deprecated 在运行时有效

 

所以要想使我们自定义的Annotation在运行时有效,必须在定义的时候指定RetentionPolicy.RUNTIME。

如何取得定义的注释信息中的值呢。

在定义的时候

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(value=RetentionPolicy.RUNTIME)            //必须指定为RUNTIME,否则不起作用
@Target(value=ElementType.METHOD)
public @interface MyAnnotation {
    public String key();               
    public String value();                
}

取出注释信息中的值

import java.lang.reflect.Method;

interface A{
    public String sayHello();
}
class Per implements A{
    @MyAnnotation(key="key",value="value")
    public String sayHello(){
        return "hello world";
    }
}

public class AnnotationDemo{
    public static void main(String []args){        
        Class <?> c = null ;        
        c = new Per().getClass() ;
        Method toM = null;
        try {
            toM = c.getMethod("sayHello");
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
        if(toM.isAnnotationPresent(MyAnnotation.class)){    // 判断是否是指定的Annotation
            MyAnnotation mda = null ;
            mda = toM.getAnnotation(MyAnnotation.class) ;   // 得到指定的Annotation
            String key = mda.key() ;                        // 取出设置的key
            String value = mda.value() ;                    // 取出设置的value
            System.out.println("key = " + key) ;
            System.out.println("value = " + value) ;
        }
    
        
    }
}

通过以上代码就可以取出在注释信息中的值。

 

总结

Annotation在使用中,肯定是结合反射,设定一些内容到方法中去,以完成特定的功能。

 

Java中的Annotation (二、自定义Annotation)

标签:

原文地址:http://www.cnblogs.com/maydayit/p/4237277.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!