(二) 注解语法

(1)一个注解是由一个注解接口定义的:

    modifiers @interface AnnotationName{
        element declaration1;
        element declaration2;
    }
 

(2)每个元素声明具有下面这种形式:

    type elementName();
    type elementName() default value;
 

例如,注解具有两个元素: assignedTo 和 severity

    public @interface BugReport{
        String assignedTo() default "[none]";
        //int severity() = 0; 经测试不能使用 = 号,int类型也是default
        int severity() default 0;
    }

 


(3)每个注解都具有下面这种形式:
@AnnotationName(elementName1=value1, elementName2=value2, ...)
例 

    @BugReport(assignedTo="Harry", serverity=10)

 其中元素的顺序无关紧要
例 

    @BugReport(severity=10, assignedTo="Harry") 与上例相同

 


如果某个元素的值未指定,就使用声明的默认值。
如果某个元素的值未指定,且没有声明的默认值,则编译无法通过。

(4)有两个特殊的快捷方式可以用来简化注解。

标记注解:如果没有指定元素,可能因为注解中没有任何元素,或所有元素都使用默认值,此时可以补使用圆括号。这样的注解称为标记注解
例 

    @BugReport

 

单值注解:如果一个元素具有特殊的名字value(该元素名必须为"value"),并且没有指定其他元素,那么就可以忽略掉这个元素名以及等号。
例 

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyListener {
        String value();
    }
 


可以将这个注解写成如下形式:

    @MyListener("string")
 

(5)所有的注解接口隐式的扩展java.lang.annotation.Annotation接口,这个接口是一个正规接口,而不是一个注解接口。

(6)无法扩展注解接口,换句话说,所有的注解接口都直接扩展直java.lang.annotation.Annotation。(但注解元素的类型可以为另一个注解)

(7)不用提供那些实现了注解接口的类,相反,虚拟机会在需要的时候产生一些代理类及对象。
例: 请求一个ActionListenerFor注解的时候,虚拟机实现了一个和下面相似的操作

    return Proxy.newProxyInstance(classLoader, ActionListenerFor.class,
        new InvocationHandler(){
            public Object invoke(Object proxy, Method m, Object[] args) throws Throwable{
                if(m.getName().equals("source")){
                    return value of source annotation;
                }
                ...
            }       
        }
    });

 
(8)注解接口中的元素声明实际上是方法声明。一个注解接口的方法可以没有任何参数,没有任何throws语句,并且它们也不能是泛型的。

(9)注解元素的类型为下列之一
一个基本类型(int, short, long, byte, char, double, float或boolean)
一个String
一个Class(具有一个可供选择的类型参数,例如 Class<? extends MyClass> )
一个enum类型
一个注解类型
一个由前面所述类型组成的数组(由数组组成的数组不是合法的元素类型)

例  一些合法的元素声明的例子

    public @interface BugReport{
   
        enum Status {UNCONFIRMED, CONFIRMED, FIXED, NOTABUC};
   
        boolean showStopper() default false;
        String assignedTo() default "[none]";
        Class<?> testCase() default Void.class;
        Status status() default Status.UNCONFIRMED;
        Reference ref() default @Reference(); //an annotation type
        String[] reportedBy();
    }

 
(10)因为注解是由编译器计算而来的,因此,所有元素值必须是编译期常量。
例 

    @BugReport(showStopper=true, assignedTo="Harry", testCase=MyTestCase.class,
        status=BugReport.Status.CONFIRMED, reportedBy={"Harry", "Carl"}, ref=@Reference(id="123"))

 (11)一个注解元素从来不能设置为null,甚至不允许其默认值为null。这样在实际应用中会相当不方便,必须使用其他的默认值,例如 "" 或者 Void.class。
       
(12)如果元素值是一个数组,要将它的值用括号括起来
例 

    @BugReport(..., reportedBy={"Harry", "Carl"})

 
如果该元素具有单值,可以忽略这些括号:

    @BugReport(..., reportedBy="Joe") // "Joe" same as {"Joe"}
 

(13)一个注解元素可以是另一个注解,那么可以创建出任意复杂的注解。
例 

    @BugReport(ref=@Reference(id="123")...)
 

(14)注意,在注解中引入循环依赖是一种错误,例如在BugReport具有一个注解类型为TestCase的元素,那么TestCase就不能再拥有一个类型为BugReport的元素。

(15)可以向注解中添加如下一些项:

类(包括enum)
接口(包括注解接口)
方法
构造器
实例成员(包含enum常量)
本地变量
参数变量

不过,对本地变量的注解只能在源码级别上进行处理,类文件无法描述本地变量,因此,所有的本地变量注解在编译完一个类的时候会被一起掉。同样地,对包的注解也只能在源码级别上进行处理。
注意:注解在文件package-info.java中,只包含包的声明,在这个文件中可以对包进行注解,这需要以注解为文件的开始。

(16)一个项可以具有多个注解,只要他们属于不同的类型即可。当注解一个特定项的时候,不能多次使用同一个注解类型。即对同一项使用多次相同的注解是错误的。
如果需要对一个项使用多次相同的注解,可以设计一个注解,它的值是一个由更简单的注解组成的数组。

    @BugReports(@BugReport(showStopper=true, reportedBy="Joe"),
        @BugReport(reportedBy={"Harry", "Carl"}))
    void myMethod()
 

 
接口 java.lang.annotation.Annotation
Class<? extends Annotation> annotationType() : 返回此 annotation 的注解类型。用于描述该注解对象的注解接口。注意:调用注解对象上的getClass方法可以返回真正的类,而不是接口。
boolean equals(Object obj) : 如果指定的对象表示在逻辑上等效于此接口的注解,则返回 true。 即other是一个作为该注解对象来实现的同一注解接口的对象,并且该对象和other的所有元素彼此相等,则返回true
int hashCode() : 返回一个与equals方法兼容、由接口名以及元素名衍生出来的此 annotation 的哈希码,具体说明如下: 一个 annotation 的哈希码是其成员(包括那些带有默认值的成员)的哈希码的和,具体说明如下: annotation 成员的哈希码是成员值哈希码的 XOR(它是 String.hashCode() 计算得到的成员名哈希码的 127 倍),具体说明如下: 成员值的哈希码取决于其类型: 基值 v 的哈希码等于 WrapperType.valueOf(v).hashCode(),其中 WrapperType 是对应 v 的基本类型的包装器类型(Byte、Character、Double、Float、Integer、Long、Short 或 Boolean)。
String toString() : 返回此 annotation 的字符串表示形式。例如 @com.shaogq.annotation.mytest.MyListener(value=abc)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值