给编译器看的注解--Annotation

本文详细介绍了Java中的Annotation,包括其作为编译器配置信息的作用,系统内置的@ Override、@ Deprecated和@ SuppressWarnings三个Annotation的使用,自定义Annotation的语法,Retention和RetentionPolicy的原理,以及如何通过反射获取Annotation信息。同时,文章还讨论了Target、Documented和Inherited等深入Annotation的知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Annotation的含义

Annotation主要服务于编译器,属于一种配置信息。在本质上,Annotation提供了一种与程序元素关联任何信息或者任何元数据的方式。Annotation可以像修饰符一样被使用,可以应用于任何程序元素(如包、类型、构造方法、方法、成员变量、参数、本地变量)的声明中。这些信息被存储在Annotation的“name=value”结构对中。事实上,Annotation类型是一种接口,能够通过java发射API(应用程序接口)的方式提供对其信息的访问。

 

2.系统内建的Annotation

JDK1.5之后的系统中,内建有3个Annotation:@Override、@Deprecated、@SuppressWarnings。

2.1@Override

@override表示方法覆写的正确性,例如,如下代码:

package 类集;

class Person{

    public String getInfo(){        // 取得信息

        return "这是一个Person类。" ;

    }

};

class Student extends Person{    // 继承此类

    @Override

    public String getinfo(){    // 覆写方法,这里覆写的方法大小写错误了,就会报错。

        return "这是一个Student类。" ;

    }

};

public class GetInterfaceDemo {

    public static void main(String[] args) throws Exception {

        Person per = new Student() ;

        System.out.println(per.getInfo()) ;    // 输出信息

    }

}

如果没有上述@override,则方法名称getInfo编写错误,大小写错误。这个时候为了保证覆写正确性,添加覆写属性,保证程序正确执行。

2.2@Deprecated

使用Deprecated注释的Annotation本身是不建议使用的操作。

package 类集;

class Demo{

    @Deprecated            // 声明不建议使用的操作

    public String getInfo(){

        return "这是一个Person类。" ;

    }

};

public class GetInterfaceDemo {

    public static void main(String[] args) throws Exception {

        Demo d = new Demo() ;

        System.out.println(d.getInfo()) ;

    }

}

以上程序并不会使得编译出差,但是会产生一个警告信息。

2.3@SuppressWarnings

用于压制警告信息。以泛型操作为例,在泛型中如果没有指定泛型类型,则使用时候肯定出现安全警告。

正常情况不使用annotation。没有指定泛型类型。

package 类集;

class Demo<T>{

    private T var ;

    public T getVar(){

        return this.var ;

    }

    public void setVar(T var){

        this.var = var ;

    }

};

public class GetInterfaceDemo {

    public static void main(String args[]){

        Demo d = new Demo();  //因为没有给泛型指定类型,这里会有警告

        d.setVar("小华");  //这里会有警告

        System.out.println("内容:" + d.getVar()) ;

    }

}

此时可以使用SuppressWarning这个Annotation将这种警告信息进行压制。注释信息表示要强制压制的信息,可以通过@SuppressWarnings(“信息”)方式进行注释,里面的信息可以用数组形式注释,例如:@SuppressWarnings({ "unchecked", "rawtypes" })。

package 类集;

class Demo<T>{

    private T var ;

    public T getVar(){

        return this.var ;

    }

    public void setVar(T var){

        this.var = var ;

    }

};

public class GetInterfaceDemo {

    @SuppressWarnings({ "unchecked", "rawtypes" })

    public static void main(String args[]){

        Demo d = new Demo() ;

        d.setVar("小华") ;

        System.out.println("内容:" + d.getVar()) ;

    }

}

 

3.自定义Annotation

自定义Annotation的语法如下

[public] @interface Annotation的名称{

  [数据类型 变量名称();]

}

在程序中只要使用了@interface声明Annotation,那么此Annotation实际上就相当于继承了java.lang.annotation.Annotation接口。例如:

@interface MyAnnotation{

  public String key();

  public String value();

}

public class TestAnnoVar{

  @MyAnnotation(key=var1,value=test)

  public static void main(String[] arg){

  System.out.println(“Hello World”);

}

}

如果在自定义Annotation中声明变量,且没有设置默认值,则在使用该Annotation时必须为变量赋值。如下为自定义Annotation中变量设置为默认值的例子:

@interface MyAnnotation{

  public String key() default “var1”;

  public String value() default “test”;

}

public class TestAnnoVar{

  @MyAnnotation()

  public static void main(String[] arg){

  System.out.println(“Hello World”);

}

}

 

4.Retention和RetentionPolicy

在注解中,可以使用Retention(中文含义为“保留”)来定义一个Annotation的保存范围,定义如下:

@Documented

@Retention(value=RUNTIME)

@Target(value=ANNOTATION)

public @interface Retention{

  RetentionPolicy value();

}

其中,@Documented有注解的作用,将自定义注解设置为文档说明信息。

RetentionPolicy是一个枚举类型,用于指定Annotation的保存范围。RetentionPolicy包含3个取值范围:

  1. SOURCE:此Annotation类型的信息只会记录在源文件中,编译时将会被编译器丢弃,及此Annotation信息不会保存在编译号的类文件中。
  2. CLASS:编译器将会把注释记录在类文件中,但不会被加载到JVM中。如果一个Annotation声明时没有指定范围,则系统默认值CLASS。
  3. RUNTIME:此Annotation类型的信息将会被保留在源文件、类文件中,在执行时也会加载到java虚拟机中,因此可以反射性读取。

 

5.反射与Annotation

注解通过反射,可以取得在一个方法上声明的全部内容。

在Filed、Method、Constructor的父类上定义了以下与Annotation发射操作相关的方法。

  1. 取得全部的Annotation;
  2. 判断操作的是否是指定的Annotation。

5.1取得全部的Annotation

例如下面代码:

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

class Info

{

@Override

@Deprecated

@SuppressWarnings( value = "" )

public String toString()

{

return "Hello World!";

}

}

public class GetAnnotations

{

public static void main( String[] args ) throws Exception

{

Class<?> cls = Class.forName( "Info" );

Method toStringMethod = cls.getMethod( "toString" );

// 取得全部的Annotation

Annotation ans[] = toStringMethod.getAnnotations();

for( int i=0; i<ans.length; ++i )

{

System.out.println( ans[i] );

}

}

}

上述代码3个内建的Annotation中只有@Deprecated是RUNTIME类型。所以只输出了Deprecated。也就是说,只有定义采用的是@Retention(value=RUNTIME)的Annotation才能在程序运行时被反射机制取得。

5.2取得指定的Annotation

例如下面代码:

import java.lang.annotation.*;

import java.lang.reflect.Method;

@Retention(value = RetentionPolicy.RUNTIME)

@interface MyAnnotation

{

public String key();

public String value();

}

class Info

{

@Override

@Deprecated

@SuppressWarnings( value = "" )

@MyAnnotation( key = "one", value = "test" )

public String toString()

{

return "hello";

}

}

public class GetAnnotation

{

public static void main( String[] args ) throws Exception

{

Class<?> cls = Class.forName( "Info" );

Method toStringMethod = cls.getMethod( "toString" );

 

// 判断该方法上是否有指定类型的Annotation存在

if( toStringMethod.isAnnotationPresent( MyAnnotation.class ) )

{

MyAnnotation my = null; // 声明Annotation的对象

my = toStringMethod.getAnnotation( MyAnnotation.class );

String key = my.key();

String value = my.value();

System.out.println( key + " --> " + value );

}

}

}

 

6.深入Annotation

在java.lang.annotation包下还有:Target、Documented、Inherited。下面分别进行介绍。

6.1Target

@Target明确指出了一个Annotation的使用位置。在@Target中存在一个ElementType[]枚举类型的变量,这个变量主要用于指定Annotation的使用权限。ElementType类定义了下面8个取值:

(1)ANNOTATION_TYPE:只能用在注释上;

(2)CONSIRUCTOR:只能用在构造方法的声明上;

(3)FOELD:只能用在字段的声明(包括枚举常量)上;

(4)LOCAL_VARIABLE:只能用在局部变量的声明上;

(5)METHOD:只能用在方法的声明上;

(6)PACKAGE:只能用在包的声明上;

(7)PARAMEIER:只能用在参数的声明上;

(8)TYPE:只能用在类、接口、枚举类型上。

如果要为value设置多个值,可以使用下面的方法:

value={ElementType.TYPE,ElementType.METHOD}

6.2Documented注释

@Documented可以将自定义的注释设置为文档说明设置信息,因此在生成javadoc时就会将该注解加入文档。

下面例子使注解可以出现在javadoc文档中:

import java.lang.annotation.*;

@Documented

@Retention(value = RetentionPolicy.RUNTIME)

public @interface MyAnnotation

{

public String key();

public String value();

}

class Info

{

@Override

@Deprecated

@SuppressWarnings(value = "")

@MyAnnotation(key = "one", value = "test" )

public String toString()

{

return "hello";

}

}

6.3Inherited

@Inherited用于标注一个父类的Annotation是否可以被子类继承,如果一个Annotation需要被其子类继承,则在声明时直接使用@Inherited注释即可。

import java.lang.annotation.*;

@Inherited

@Documented

@Retention( value = RetentionPolicy.RUNTIME )

public @interface InheritedAnnotation

{

}

@InheritedAnnotation

class Person

{

}

class Student extends Person

{

}

虽然Student类上并没有直接使用InheritedAnnotation,但是却从Person类上继承了下来,所以可以通过反射极值取出该Annotation。

 

注意点

1.想配合反射机制就必须设置@Retention(value=RetentionPolicy.RUNTIME)。

2.@Target可以指定一个Annotation的使用范围。

3.如果一个annotation希望被使用类的子类所继承,则要使用@Inherited Annotation。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值