Java注解
@FunctionalInterface public interface FunInterface { static void Foo() { System.out.println("foo 类方法");}}</span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> bar() { System.out.println(</span>"bar默认方法"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">void</span> test(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">只定义一个抽象方法</span>
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;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Inheritable {}
如果某个类使用了@Inheritable 修饰,则该类的子类将自动使用 @Inheritable 修饰。
@Inheritable class Base {}
public class InheritableTest extends Base{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) { System.out.println(InheritableTest.</span><span style="color: rgba(0, 0, 255, 1)">class</span>.isAnnotationPresent(Inheritable.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)); }
}
//定义一个简单的 Annotation 类型 public @interface Test {}
定义了该Annotation 之后,可以在程序的任何地方使用该 Annotation,使用 Annotation 的语法非常类似于 public、final 这样的修饰符,通常可用于修饰程序中的类、方法、变量、接口等定义。通常会把 Annotation 放在所有修饰符之前,而且由于使用 Annotation 时可能还需要为成员变量指定值,因而 Annotation 的长度可能较长,所以通常把 Annotation 另放一行,如下程序所示:
@Test public class MyClass {...}
Annotation 还可以带成员变量,Annotation 的成员变量在 Annotation 定义中以无形参的方法形式来声明,其方法名和返回值定义了该成员变量的名字和类型。如:
public @interface MyTag { //定义带两个成员变量的 Annotation //Annotation 中的成员变量以方法的形式来定义 String name(); int age();}
一旦在Annotation 里定义了成员变量之后,使用该 Annotation 时就应该为该 Annotation 的成员变量指定值。如:
public class Test { //使用带成员变量的 Annotation 时,需要为成员变量赋值 @MyTag(name="xx", age=6) public void info() {}
}
也可以在定义Annotation 的成员变量时为其指定初始值(默认值),指定成员变量的初始值可使用 default 关键字。
public @interface MyTag { //定义带两个成员变量的 Annotation //Annotation 中的成员变量以方法的形式来定义 String name() default "Jason"; int age() default 26; }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) //定义一个标记注解,不包含任何成员变量,即不可传入元数据 public @interface Testable {}
@Retention 注解指定 Testable 注解可以保留到运行时(JVM 可以提取到该Annotation 的信息),而 @Target 注解指定 @Testable 只能修饰方法。
package com.turing.annotation.test; public class MyTest { @Testable public static void m1() {} </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m2() { } @Testable </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m3() { </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("参数出错了!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m4() { } @Testable </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m5() { } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m6() { } @Testable </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m7() { </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RuntimeException("程序业务出现异常!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> m8() { }
}
仅仅使用注解来标记程序元素对程序是不会有任何影响的,这也是 Java 注解的一条重要原则。为了让程序中的这些注解起作用,接下来必须为这些注解提供一个注解处理工具。
import java.lang.reflect.Method;public class ProcessorTest {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> process(String clazz) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> SecurityException, ClassNotFoundException { </span><span style="color: rgba(0, 0, 255, 1)">int</span> passed = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">int</span> failed = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 遍历clazz对应的类里的所有方法</span> <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Method m : Class.forName(clazz).getMethods()) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果该方法使用了@Testable修饰</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (m.isAnnotationPresent(Testable.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { m.invoke(</span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">); passed</span>++<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex) { System.out.println(</span>"方法" + m + "运行失败,异常:" +<span style="color: rgba(0, 0, 0, 1)"> ex.getCause()); failed</span>++<span style="color: rgba(0, 0, 0, 1)">; } } } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 统计测试结果</span>
System.out.println(
"共运行了:" + (passed + failed) + "个方法,其中:\n" + "失败了:" + failed + "个,\n" + "成功了:" + passed + "个!");
}
}
主程序:
public class RunTests { public static void main(String[] args) { try { ProcessorTest.process("com.turing.annotation.test.MyTest");} catch (SecurityException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace();} } }
Outputs:
方法 public static void com.turing.annotation.test.MyTest.m3() 运行失败,异常:java.lang.IllegalArgumentException: 参数出错了! 方法 public static void com.turing.annotation.test.MyTest.m7() 运行失败,异常:java.lang.RuntimeException: 程序业务出现异常! 共运行了: 4 个方法,其中: 失败了:2 个, 成功了: 2 个!