Java必备:基本Annotation




Java必备:基本Annotation


一、Annotation简介 


  • 从Java1.5开始,Java增加了元数据(MetaData)的支持,也就是Annotation(注释); 

  • Annotation能被用来为程序元素(类、方法、成员变量等)设置元数据 

  • Annotation不能影响程序代码的执行,无论添加、删除Annotation,代码始终如一的执行 

  • 如果希望让程序中的Annotataion能在 运行时其一定作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,这些工具统称APT(Annotion Processing Tool); 

 

二、三个基本的Annotation如下 

  • @Override:限定重写父类方法 

    • 用来指定方法覆盖的,它可以强制一个子类必须要覆盖父类的方法 

    • 只能用作于方法,不能用于作用其他程序元素 

    • 主要是帮助我们避免一些低级错误 

public class Fruit {   
	    public void foo(){   
	        System.out.println("水果的info方法。。。");   
	    }   
	}   
	   
	class Apple extends Fruit   
	{   
	    //使用@Override指定下面方法必须重写父类方法   
	    @Override   
	    public  void foo() {   
	         System.out.println("苹果重写水果的info方法...");   
	     }   
	}


<span style="font-size:18px;"><span style="font-family:SimSun;">public class Fruit { 
    public void foo(){ 
        System.out.println("水果的info方法。。。"); 
    } 
} 
 
class Apple extends Fruit 
{ 
    //使用@Override指定下面方法必须重写父类方法 
    @Override 
    public void foo() { 
         System.out.println("苹果重写水果的info方法..."); 
     } 
} <span style="color:windowtext;line-height: 15px; background-color: transparent;"> </span></span></span>

  • @Deprecated:标记已过时 

    • 用于标识某个程序元素(类、方法等)已过时,当其他程序使用已过时的类、方法时,编译器将会给出警告 

public class DeprecatedTest {

	public static void main(String[] args) {   
	        //下面使用info方法时将会被编译器警告   
		new Apple1().info();   
	}   
	 
	
}

class Apple1{   
	//定义info方法已经过时   
	@Deprecated   
	public void info(){   
		System.out.println("Apple的info方法");   
	}   
}   

<span style="font-family:SimSun;font-size:18px;">class Apple1{ 
    //定义info方法已经过时 
    @Deprecated 
    public void info(){ 
        System.out.println("Apple的info方法"); 
    } 
} 
 
public class DeprecatedTest { 
    public static void main(String[] args) { 
        //下面使用info方法时将会被编译器警告 
        new Apple1().info(); 
    } 
} </span>

  • @SuppressWarnings:抑制编译器警告 

    • 指示被Annotation标识的程序元素(以及在该程序元素中的所有字元素)取消显示指定的编译器警告 

    • 一直作用于该程序元素的所有子元素


   //关闭整个类里的编译器警告   
   @SuppressWarnings(value="unchecked")  
   public class SuppressWarningsTest {
       public static void main(String[] args) {   
           List<String> myList = new ArrayList();   
           myList.add("java");   
       }   
   }



三、JDK的Annotation


一、使用@Retention 

  • 只能修饰一个Annotation定义,用于指定该Annotation可以保留多长时间 

  • 包含一个RetentionPolicy类型的value成员变量 

    • RetentionPolicy.CLASS:编译器把注释记录在class文件中,当运行Java程序时,JVM不在保留注释,默认值 

    • RetentionPolicy.RUNTIME:编译器将把注释记录在class文件中,当运行Java程序时,JVM也会保留注释,程序可以通过反射获取该注释 

    • RetentionPolicy.SOURCE:编译器直接丢弃这种策略的注释 

注意:interface 是接口 @interface是自定义的annotation


//定义下面的Testable注解保留到运行时 
@Retention(value="RetentionPolicy.RUNTIME") 
public @interface Testable{} 



二、使用@Target 

  • 用于修饰一个Annotation定义,指定被修饰的Annotation能用于修饰哪些程序元素 

  • 包含一个名为value的成员变量 

    • ElementType.ANNOTATION_TYPE:只能修饰Annotation 

    • ElementType.CONSTRUCTOR:只能修饰构造器 

    • ElementType.FIELD:只能修饰成员变量 

    • ElementType.LOCAL_VARIABLE:只能修饰局部变量 

    • ElementType.METHOD:只能修饰方法定义 

    • ElementType.PACKAGE:只能修饰包定义 

    • ElementType.PARAMETER:只能修饰参数 

    • ElementType.TYPE:只能修饰类、接口(包括注释型)或枚举定义


 //定义下面的ActionListenerFor注解只能用于成员变量   
    @Target(ElementType.FIELD)   
    public @interface ActionListenerFor{}; 

三、使用@Documented  

  • 用于指定该元Annotation修饰的Annotation类将被javadoc工具提取成文档 

  

@Retention(value="RetentionPolicy.RUNTIME")   
    @Target(ElementType.METHOD)   
    //定义下面的Testable注解将被javadoc提取   
    @Documented   
    public @interface Testable{} 

 
使用@Inherited 
  
  • 指定它修饰的Annotation将具有继承性 

  • 如果某个类使用了A Annotation(定义该Annotation使用了@Inherited修饰)修饰,则其子类将自动具有A注释 

 @Target (ElementType.TYPE) 
    @Retention(RetentionPolicy.RUNTIME) 
    @Inherited 
    public @interface Inheritable { 
    } 
     
    //使用@Inheritable修饰Base类 
    @Inheritable 
    class Base{ 
    } 
    //TestInheritable类只是继承了Base类 
    //并未直接使用@Inheritable Annotation修饰 
    public class InheritableTest extends Base{ 
        public static void main(String[] args){ 
            System.out.println(InheritableTest.class.isAnnotationPresent(Inheritable.class)); 
        } 
    }   
  


四、自定义Annotation步骤 

  1. 使用@interface关键字定义新的Annotation 

//定义一个简单的Annotation类型 
public @interface Test{ 
}

//定义一个简单的Annotation类型 
public @interface Test{ 
}

  1. 用于修饰程序的类、方法、变量、接口等定义 

//使用@Test修饰类定义 
@Test 
public class MyClass{ 
} 
 
public class MyClass{ 
    //使用@TestAnnotaion修饰方法 
    @Test 
    public void info(){ 
    } 
} 

//使用@Test修饰类定义 
@Test 
public class MyClass{ 
} 
 
public class MyClass{ 
    //使用@TestAnnotaion修饰方法 
    @Test 
    public void info(){ 
    } 
} 

  1. 定义Annotation成员变量 

public @interface MyTag{ 
    //定义两个成员变量的Annotation 
    //Annotation中的成员变量以方法的形式定义 
    String name(); 
    int age(); 
} 

 
public @interface MyTag{ 
    //定义两个成员变量的Annotation 
    //Annotation中的成员变量以方法的形式定义 
    String name(); 
    int age(); 
} 

  1. 使用该Annotation时,为该Annotation的成员变量指定值 

public class Test{ 
    //使用成员变量的Annotation时,需要为成员变量指定值 
    @MyTag(name="xx",age=6) 
    public void info(){ 
        … 
    } 
    ... 
} 

public class Test{ 
    //使用成员变量的Annotation时,需要为成员变量指定值 
    @MyTag(name="xx",age=6) 
    public void info(){ 
        … 
    } 
    ... 
} <span style="color: windowtext; line-height: 15px; font-family: Calibri, sans-serif; font-size: 10pt; background-color: transparent;"> </span>

  1. 我们还可以为Annotation指定初始值,使用default关键字 

public @interface MyTag{ 
    //定义两个成员变量的Annotation 
    //以default为两个成员变量指定初始值 
    String name() default "yeeku"; 
    int age() default 32; 
} 

public @interface MyTag{ 
    //定义两个成员变量的Annotation 
    //以default为两个成员变量指定初始值 
    String name() default "yeeku"; 
    int age() default 32; 
} 

  • 如果为Annotation的成员变量指定了默认值,使用时则可以不为这些成员变量指定值 

  • 当然,如果为MyTag的成员变量指定了值,则默认值不会起作用 

 

二、Annotation分类 

  • 根据Annotation是否包含成员变量,我们可以把Annotation分为如下两类 

    • 标记Annotation:没有成员定义,仅使用自身存在与否来为我们提供信息 

    • 元数据Annotation:包含成员变量 

     

三、提取Annotation的信息 

  • Annotatoin不会自己生效,必须由开发者提供相应的工具来提取并处理Annotation信息 

  • 当一个Annotaion类型被定义为运行时Annotaion后,该Annotation才会在运行时可见,JVM才会装载*.class文件时读取保存在class文件中的Annotation 

 

  • Annotaion接口:代表程序元素前面的注释 

  • AnnotatedElement接口:代表程序中可以接受注释的程序元素 

    • 主要有如下几个实现类:Class,Constructor,Field,Method,Package 

    • 通过反射获取某个类的AnnotatedElement对象,调用该对象的如下方法访问Annotataion信息 

      • getAnnotation(Class<T> annotationClass):返回该程序上存在的制定类型的注释,如果该类型的注释不存在,则返回null 

      • Annotation[] getAnnotations():返回该程序元素上所存在的所有注释 

      • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该程序元素上是否存在指定类型的注释,如果存在返回true,否则返回false 

//获取MyTest类的info方法的所有注释 
try { 
    Annotation[] aArray = Class.forName("codes.chapter14.class3.MyTest").getMethod("m1").getAnnotations(); 
    //遍历所有注释 
    for(Annotation an : aArray){ 
        System.out.println(an); 
    } 
} catch (ClassNotFoundException e) { 
    e.printStackTrace(); 
} catch (NoSuchMethodException e) { 
    e.printStackTrace(); 
} catch (SecurityException e) { 
    e.printStackTrace(); 
} 
 
 
// 获取对象的MyTest 对象的m8方法所包含的所有注释 
// 注意,只有在运行时保留的Annotation才能被获取信息 
try { 
    MyTest myTest = new MyTest(); 
    Annotation[] annotations = myTest.getClass().getMethod("m8").getAnnotations(); 
    // 遍历每个注释 
    for (Annotation annotation : annotations) { 
        if (annotation instanceof MyTag) { 
             System.out.println("Annotation is:" + annotation); 
            // 将tag强制类型转换为MyTag 
            System.out.println("annotation.name():"+ ((MyTag) annotation).name()); 
            System.out.println("annotation.age():"+ ((MyTag) annotation).age()); 
        } 
    } 
} catch (NoSuchMethodException e) { 
    e.printStackTrace(); 
} catch (SecurityException e) { 
    e.printStackTrace(); 
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值