`

Java Annotation注释语法参考

    博客分类:
  • java
阅读更多

 

JAVA从J2SE5开始提供名为annotation(注释,标注)的功能。Java的annotation,可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信息。附加在package, class, method, field等上的Annotation,如果没有外部解析工具等对其加以解析和处理的情况,本身不会对Java的源代码或class等产生任何影响,也不会对它们的执行产生任何影响。 

但借助外部工具,比如javac,EJB容器等,可以对附加在package, class, method, field的annotation进行解析,可以根据annotation而做出相应的处理,比如运行时改变对象/方法的行为。 
Java标准Annotation 

@Deprecated 相当于Javadoc的@deprecated,被@Deprecated标注的对象class, method等被注明为不推荐使用。主要用于javac等编译工具。 
@Override 注明对象method重载了父类的方法。javac等编译工具编译时会根据此Annotation判断重载方法是否正确。 
@SuppressWarnings 告诉javac等编译器忽略所指定的特定的警告信息。 
@Target 被定义的annotation可以附加在那些对象上。 
@Retention annotation的作用期间。 
Java标准Annotation的使用 
@Deprecated: 
@Deprecated 
public class TestBean { 
    … 

@SuppressWarnings: 
@SuppressWarnings("serial ") 
public class TestBean implements java.io.Serializable { 
    … 

@SuppressWarnings(value = {"serial ", "unchecked "}) 
public String doSth() { 
    … 

@Override: 
@Override 
public String doSth() { 
    … 


Annotation的定义 
定义方法: 
@interface Annotation名 {定义体} 

定义例1: 
public @interface MyAnnotation {} 
该例定义了一个无任何属性/方法的Annotation。 

定义例2: 
public @interface MyAnnotation { 
    public String value(); 

该例定义了只有一个方法为value()的Annotation。一般来说,只有一个方法的Annotation,方法名一定定义为value。 
定义例3: 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface MyAnnotation { 
    public String value(); 
    public String [] multiValues(); 
    int number() default 0; 
    

该例定义了一个具有多方法的Annotation。并设置其中一个方法number的默认值为0。multiValues 方法定义为数组类型。Annotation定义可以用MetaAnnotation(元注释)修饰。MetaAnnotation有以下2个: 
@Retention 
@Target 

我们将在以下对@Retention与@Target加以说明。 

@Retention 
@Retention 可以设置为RetentionPolicy类型的值。 
例: 
@Retention(RetentionPolicy.RUNTIME) 

RetentionPolicy的值 说明 
RetentionPolicy.CLASS annotation信息将被编译器编译时保存在class文件中,但执行时不会在VM装载。也就是说不能在执行时动态取得annotation信息。未设置@Retention时这将是默认设置值。 
RetentionPolicy.RUNTIME annotation信息将被编译器编译时保存在class文件中,执行时也会被VM装载。 
RetentionPolicy.SOURCE annotation信息将被编译器编译时舍弃掉。 
@Target 

@Target表明Annotation可以附加在哪种JAVA元素之上,可以设置为java.lang.annotation.ElementType数组类型的值。 
使用例1: 
@Target(ElementType.METHOD) 


使用例2: 
@Target(value={ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD}) 


ElementType是一个枚举类型,它具有以下定义: 
ElementType值 说明 
ElementType.ANNOTATION_TYPE 应用于其他注解的元注解 
ElementType.CONSTRUCTOR 构造函数 
ElementType.FIELD 字段 
ElementType.LOCAL_VARIABLE 方法中的本地变量 
ElementType.METHOD 方法 
ElementType.PACKAGE 包 
ElementType.PARAMETER 方法的参数 
ElementType.TYPE 类,接口或者枚举声明 

自定义 Java Annotation 



Annotation是一种特殊的interface。所以可以在annotation里定义方法,属性;也可以让某个类从annotation继承(implements)。 

下面从简单地范例开始,让我们一步步加深对annotation的了解。 
无任何方法/属性Annotation范例: 

MyAnnotation0.java 
package com.test.annotation; 

public @interface MyAnnotation0 { 
    


MyAnnotation0为一个无任何方法和属性的annotation。 

使用MyAnnotation0: 
TestMyAnnotation0.java 
@MyAnnotation0 
public class TestMyAnnotation0 { 
    @MyAnnotation0 
    public void testMethod() { 

    } 

具有一个value方法Annotation范例: 
MyAnnotation1.java 
public @interface MyAnnotation1 { 
    
    /** 
     * value method 
     * @return value 
     */ 
    public String value(); 


MyAnnotation1具有一个名为value的方法。 

MyAnnotation1使用: 
TestMyAnnotation1.java 
@MyAnnotation1("hello ") 
public class TestMyAnnotation1 { 
    @MyAnnotation1(value="world ") 
    public void testMethod() { 
    } 


可以通过@Annotation名(方法名1=值1, 方法名2=值2, …)的形式给annotation赋值。只有一个方法的时候,可以直接省略为:@Annotation名(值1) 的赋值形式。当方法返回一个数组时,可以用 方法名={值1, 值2, …}给其赋值。 
具有一个value方法和一个属性Annotation范例: 

如果必要,还可以在annotation里为其定义属性。如下: 
MyAnnotation2.java 
@interface MyAnnotation2 { 
    public String value(); 
    public String myProperty = "hello world "; 


其中,myProperty只能申明为public或无public修饰(无public修饰时也默认为public)为static, final属性(即使不写也默认为static, final)。 

使用例: 
TestMyAnnotation2 
class TestMyAnnotation2 { 
    public static void main(String[] args) { 
        System.out.println(MyAnnotation2.myProperty); 
    } 

    @MyAnnotation2("") 
    public void testMethod1() { 
    } 


上例会打印出: 
hello world 


复杂型annotation的定义与使用 

本节介绍较为复杂的annotation定义与使用。 
先看代码: 
MyAnnotation3.java 
public @interface MyAnnotation3 { 
    public String value(); 
    public String[] multiValues(); 
    int number() default 0; 


MyAnnotation3具有一个返回String的value方法,返回String[]的multiValues 方法;还有一个返回int 的number方法。其中number方法具有默认值0。 

使用例: 
TestMyAnnotation3.java 
class TestMyAnnotation3 { 
    @MyAnnotation3(value = "call testMethod1 ", multiValues={"1 ", "2 "}, number = 1) 
    public void testMethod1() { 

    } 

    @MyAnnotation3(value = "call testMethod2 ", multiValues={"1 ", "2 "}) 
    public void testMethod2() { 

    } 


number具有默认值,所以标注时可以不为其赋值。其余方法则必须通过上面介绍的方法赋值。multiValues返回一个String[]数组,所以可以通过multiValues={"1", "2"}为其赋值。 
这样说来,annotation到底能起什么作用呢? 
1,    编译工具或其他工具可以根据被附加在代码里的annotation信息自动生成配置文件或文档等外部文件。 
比如,sun公司就提供了apt(Annotation Processing Tool) 工具,apt工具是一个可以处理annotation的命令行工具,apt提供了在编译期针对源代码级别的解析,并可以在解析时生成新的源代码和其他文件,同时还可以对生成的源代码进行编译。 
2,    其他程序可以在运行时动态解析将要被执行的程序里的annotation信息,并根据被附加的annotation信息来执行不同的操作。 
比如,EJB3规范就比较广泛地使用了annotation特性。比如只要在POJO为class注明@Stateless注释,EJB容器便会根据此 annotation把该POJO注册为无状态的Session Bean。EJB3使用了annotation大大地简化了EJB的开发和配置过程。我们会在其他文章里专门介绍EJB Annotation的原理与使用方法,这里不做详述。 

本文通过一个简单地例子来说明怎么在运行期动态解析annotation。Apt工具的使用我们会在近期其他文章里对其加以介绍。 

比如,我们定义了MyAnnotation3注释: 

MyAnnotation3.java 
package com.test.annotation; 

import java.lang.annotation.Annotation; 
import java.lang.annotation.Inherited; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Retention(RetentionPolicy.RUNTIME) 
public @interface MyAnnotation3 { 
    public String value(); 
    public String[] multiValues(); 
    int number() default 0; 


上面定义了一个名为MyAnnotation3的注释。 

我们再定义一个GetMyAnnotation类,该类使用了MyAnnotation3注释: 
GetMyAnnotation.java: 
package com.test.annotation.test; 

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

import javax.ejb.EJB; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 

import com.test.annotation.MyAnnotation3; 

// 为GetMyAnnotation类附加MyAnnotation3 注释 
@MyAnnotation3(value = "Class GetMyAnnotation ", multiValues = {"1 ","2 "}) 
public class GetMyAnnotation { 
    // 为testField1属性附加MyAnnotation3 注释 
    @MyAnnotation3(value = "call testField1 ", multiValues={"1 "}, number = 1) 
    private String testField1; 

    // 为testMethod1方法附加MyAnnotation3 注释 
    @MyAnnotation3(value = "call testMethod1 ", multiValues={"1 ", "2 "}, number = 1) 
    public void testMethod1() { 

    } 

    @Deprecated 
    @MyAnnotation3(value = "call testMethod2 ", multiValues={"3 ", "4 ", "5 "}) 
    public void testMethod2() { 

    } 


上面的例子GetMyAnnotation非常简单,里面没有任何功能,但是分别为类(class),属性(field),方法(method)申明(附加)了MyAnnotation3 注释。 

下面我们用程序TestMyAnnotation3对GetMyAnnotation里MyAnnotation3注释进行解析。 

运行时解析annotation 
TestMyAnnotation3.java 
public class TestMyAnnotation3 { 

    public static void main(String[] args) { 
        System.out.println("--Class Annotations-- "); 
        if (GetMyAnnotation.class.isAnnotationPresent(MyAnnotation3.class )) { 
            System.out.println("[GetMyAnnotation].annotation: "); 
            MyAnnotation3 classAnnotation = GetMyAnnotation.class.getAnnotation(MyAnnotation3.class ); 
            printMyAnnotation3(classAnnotation); 
        } 
        
        
        System.out.println("--Fields Annotations-- "); 
        Field [] fields = GetMyAnnotation.class.getDeclaredFields(); 
        for (Field field : fields) { 
            if (field.isAnnotationPresent(MyAnnotation3.class )) { 
                System.out.println("[GetMyAnnotation. " + field.getName() + "].annotation: "); 
                MyAnnotation3 fieldAnnotation = field.getAnnotation(MyAnnotation3.class ); 
                printMyAnnotation3(fieldAnnotation); 
            } 
        } 
        
        System.out.println("--Methods Annotations-- "); 
        Method[] methods = GetMyAnnotation.class.getDeclaredMethods(); 
        for (Method method : methods) { 
            System.out.println("[GetMyAnnotation. " + method.getName() + "].annotation: "); 
            if (method.isAnnotationPresent(MyAnnotation3.class )) { 
                MyAnnotation3 methodAnnotation = method.getAnnotation(MyAnnotation3.class ); 
                printMyAnnotation3(methodAnnotation);  
            } 
        } 
    } 
    
    private static void printMyAnnotation3(MyAnnotation3 annotation3) { 
        if (annotation3 == null ) { 
            return; 
        } 
        
        System.out.println("{value= " + annotation3.value()); 
        
        String multiValues = ""; 
        for (String value: annotation3.multiValues()) { 
            multiValues += ", " + value; 
        } 
        
        System.out.println("multiValues= " + multiValues); 
        
        System.out.println("number= " + annotation3.number() + "} "); 
    } 



输出: 
--Class Annotations-- 
[GetMyAnnotation].annotation: 
{value=Class GetMyAnnotation 
multiValues=,1,2 
number=0} 
--Fields Annotations-- 
[GetMyAnnotation.testField1].annotation: 
{value=call testField1 
multiValues=,1 
number=1} 
--Methods Annotations-- 
[GetMyAnnotation.testMethod1].annotation: 
{value=call testMethod1 
multiValues=,1,2 
number=1} 
[GetMyAnnotation.testMethod2].annotation: 
{value=call testMethod2 
multiValues=,3,4,5 
number=0} 



JDK1.5以后的版本提供的跟annotation有关的接口: 
interface java.lang.reflect.AnnotatedElement { 
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); 
    <T extends Annotation> T getAnnotation(Class<T> annotationClass); 
    Annotation[] getAnnotations(); 
    Annotation[] getDeclaredAnnotations(); 


该接口主要用来取得附加在类(class),构造方法(constructor),属性(field),方法(method),包(package)上的annotation信息。 

JDK1.5与此有关的几个类都实现了AnnotatedElement接口: 
java.lang.reflect.AccessibleObject, 
java.lang.reflect.Class, 
java.lang.reflect.Constructor, 
java.lang.reflect.Field, 
java.lang.reflect.Method, 
java.lang.reflect.Package 

所以可以利用反射(reflection)功能在程序里动态解析附加的annotation信息。 


总结: 
本文通过举例简单地说明了怎么动态解析annotation,大家可以举一反三,利用Java的annotation特性,完成更复杂功能等。    
分享到:
评论

相关推荐

    java或Java框架中常用的注解及其作用详解_资料.docx

    java或Java框架中常用的注解及其作用详解:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过...

    java高手真经 光盘源码

    java高手真经 全光盘源代码 打包rar 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例HelloWorld demo.zip 03.Eclipse入门样例...javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    Java高手真经(编程基础卷)光盘全部源码 免积分

    看到那些要积分的很不酸,发布免费版本。 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例HelloWorld demo.zip 03.Eclipse入门...javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    graphql-java-annotations:Java的GraphQL注释

    该库为GraphQL模式定义提供了基于注释的语法。 如果您想使用使用graphql-java-annotations创建graphql spring引导服务器的工具,则可以查看库。 目录 入门 (Gradle语法) dependencies { compile " io.github....

    Java高手真经(编程基础卷)光盘全部源码

    看到很多人都分卷打包的,下载很是不方便,还浪费积分,我就整合压缩打包到一个包里面,里面包含全部源码 源码目录如下: ...javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    JAVA上百实例源码以及开源项目

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    JAVA上百实例源码以及开源项目源代码

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    \java超强笔记(超级经典)

    四种元注释:java.lang.annotation中的类 元注释:注释注释的注释,用来限定注释的特征 @Terget 用来限定某个注释的使用范围,可以对什么元素进行注释 @Retention 用来描述注释的有效范围 @Inherited ...

    java高级特性,涵盖了多种java常用的一些例子

    Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节...

    疯狂JAVA讲义

    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6...

    Hibernate注释大全收藏

    Hibernate注释大全收藏 声明实体Bean @Entity public class Flight implements Serializable { Long id; @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } } @Entity ...

    AnnotationKit:使用Objective-C的注释实现

    注释是一种语法元数据的形式,可以添加到Objective-C源代码中,例如java注释。 0x01它能做什么? @when用于事件调度。 @When(AppLaunched,ViewController, @selector ( doLaunched: )) + ( void )doLaunched:( ...

    java8看不到源码-htl-examples:AEMHTL示例

    java8 看不到源码htl-例子 AEM 兼容性 该软件包仅与 AEM6.4 SP2 及更高版本兼容。 它使用 OSGi r7 注释和 HTL 1.4 语法。 使用aem核心组件: aem acs 通讯: 包含的例子 OSGi r7 注释的使用示例 HTL 1.4 语法的一些...

    管理系统javasal源码-storage:存储相关的一些代码

    管理系统java sal源码 storage 本库说明: 本库主要包含存储相关的内容, 如:磁盘,卷,目录,文件,流,硬链接,符号连接,挂载点,分页文件,稀疏文件,压缩,版本,哈希,签名,权限,元数据等。 特别注释: 1....

    jDialects:jDialects是一种数据库方言工具(注意

    从Annotation创建DDL:提供对一些主要的JPA注解的支持从Java方法创建DDL:提供Java方法配置来创建DDL,同样的语法也可以在运行期修改配置。从数据库生成实体类源码:可以读取数据库结构,生成注解风格的实体类POJO或...

    play框架手册

    But you can define some interceptors in a totally different class, and link them with any controller using the @With annotation.由于java不允许多继承,通过控制器继承特点来应用拦截器就受到极大的限制。...

    play framework 框架手册 word 版

    But you can define some interceptors in a totally different class, and link them with any controller using the @With annotation.由于java不允许多继承,通过控制器继承特点来应用拦截器就受到极大的限制。...

Global site tag (gtag.js) - Google Analytics