【13-Annotation】
Annotation
5个基本的Annotation
•@Override
•@Deprecated
•@SuppressWarnings
•@SafeVarargs
•@FunctionalInterface
使用自定义Annotation
•使用@interface定义Annotation •使用Annotation修饰程序中的类、方法、变量、接口等定义,通常我们会把Annotation放在所有修饰符之前。 •定义带成员变量的Annotation。 •为Annotation的成员变量指定初始值。
提取Annotation信息
•Annotation接口来代表程序元素前面的注释,该接口是所有Annotation类型的父接口。 • AnnotatedElement接口代表程序中可以接受注释的程序元素。 •调用AnnotatedElement对象的如下三个方法来访问Annotation信息: –getAnnotation(Class<T> annotationClass):返回该程序元素上存在的、指定类型的注释,如果该类型的注释不存在,则返回null。 –Annotation[] getAnnotations():返回该程序元素上存在的所有注释。 –boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注释,存在则返回true,否则返回false。
JDK的元Annotation
•使用@Retention •使用@Target •使用@Documented •使用@Inherited
Java 8新增的重复注解
•在Java 8以前,同一个程序元素前最多只能使用一个相同类型的Annotation;如果需要在同一个元素前使用多个相同类型的Annotation,则必须使用Annotation“容器”。 •为了将该注解改造成重复注解,需要使用@Repeatable修饰该注解,使用@Repeatable时必须为value成员变量指定值。
Java 8新增的Type Annotation
•Java 8为ElementType枚举增加了TYPE_PARAMETER、TYPE_USE两个枚举值,这样就允许 定义枚举时使用@Target(ElementType.TYPE_USE)修饰,这种注解被称为Type Annotation(类型注解),Type Annotation可用在任何用到类型的地方。
•从Java 8开始,Type Annotation可以在任何用到类型的地方使用。
APT简介
•APT(annotation processing tool)是一种处理注释的工具,它对源代码文件进行检测找出其中 的Annotation后,对Annotation进行额外的处理。
•Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其 它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源代码文件和原 来的源文件,将它们一起生成class文件。
开发用户自定义APT
•为了使用系统的APT工具来读取源文件中的Annotation,程序员必须自定义一个Annotation处理器,编写Annotation处理器需要使用JDK lib目录中的tools.jar里的如下4个包: –com.sun.mirror.apt:和APT交互的接口。 –com.sun.mirror.declaration:包含各种封装类成员、类方法、类声明的接口。 –com.sun.mirror.type:包含各种封装源代码中程序元素的接口。 –com.sun.mirror.util:提供了用于处理类型和声明的一些工具。
class Apple { // 定义info方法已过时 @Deprecated public void info() { System.out.println("Apple的info方法"); } } public class DeprecatedTest { public static void main(String[] args) { // 下面使用info方法时将会被编译器警告 new Apple().info(); } } public class ErrorUtils { @SafeVarargs public static void faultyMethod(List<String>... listStrArray) { // Java语言不允许创建泛型数组,因此listArray只能被当成List[]处理 // 此时相当于把List<String>赋给了List,已经发生了“擦除” List[] listArray = listStrArray; List<Integer> myList = new ArrayList<Integer>(); myList.add(new Random().nextInt(100)); // 把listArray的第一个元素赋为myList listArray[0] = myList; String s = listStrArray[0].get(0); } } public class ErrorUtilsTest { public static void main(String[] args) { ErrorUtils.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!")); } } public class Fruit { public void info() { System.out.println("水果的info方法..."); } } class Apple extends Fruit { // 使用@Override指定下面方法必须重写父类方法 @Override public void inf0() { System.out.println("苹果重写水果的info方法..."); } } @FunctionalInterface public interface FunInterface { static void foo() { System.out.println("foo类方法"); } default void bar() { System.out.println("bar默认方法"); } void test(); // 只定义一个抽象方法 void abc(); } // 关闭整个类里的编译器警告 @SuppressWarnings(value = "unchecked") public class SuppressWarningsTest { public static void main(String[] args) { List<String> myList = new ArrayList(); // ① } }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface Inheritable { } // 使用@Inheritable修饰的Base类 @Inheritable class Base { } // TestInheritable类只是继承了Base类, // 并未直接使用@Inheritable Annotiation修饰 public class InheritableTest extends Base { public static void main(String[] args) { // 打印TestInheritable类是否具有@Inheritable修饰 System.out.println(InheritableTest.class .isAnnotationPresent(Inheritable.class)); } } public class MyTest { // 使用@Test修饰info方法 @Testable public void info() { System.out.println("info方法..."); } } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) // 定义Testable Annotation将被javadoc工具提取 @Documented public @interface Testable { } public class MyTest { // 使用@Testable注解指定该方法是可测试的 @Testable public static void m1() { } public static void m2() { } // 使用@Testable注解指定该方法是可测试的 @Testable public static void m3() { throw new IllegalArgumentException("参数出错了!"); } public static void m4() { } // 使用@Testable注解指定该方法是可测试的 @Testable public static void m5() { } public static void m6() { } // 使用@Testable注解指定该方法是可测试的 @Testable public static void m7() { throw new RuntimeException("程序业务出现异常!"); } public static void m8() { } } public class ProcessorTest { public static void process(String clazz) throws ClassNotFoundException { int passed = 0; int failed = 0; // 遍历clazz对应的类里的所有方法 for (Method m : Class.forName(clazz).getMethods()) { // 如果该方法使用了@Testable修饰 if (m.isAnnotationPresent(Testable.class)) { try { // 调用m方法 m.invoke(null); // 测试成功,passed计数器加1 passed++; } catch (Exception ex) { System.out.println("方法" + m + "运行失败,异常:" + ex.getCause()); // 测试出现异常,failed计数器加1 failed++; } } } // 统计测试结果 System.out.println("共运行了:" + (passed + failed) + "个方法,其中:\n" + "失败了:" + failed + "个,\n" + "成功了:" + passed + "个!"); } } public class RunTests { public static void main(String[] args) throws Exception { // 处理MyTest类 ProcessorTest.process("MyTest"); } } // 使用JDK的元数据Annotation:Retention @Retention(RetentionPolicy.RUNTIME) // 使用JDK的元数据Annotation:Target @Target(ElementType.METHOD) // 定义一个标记注解,不包含任何成员变量,即不可传入元数据 public @interface Testable { }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ActionListenerFor { // 定义一个成员变量,用于设置元数据 // 该listener成员变量用于保存监听器实现类 Class<? extends ActionListener> listener(); } public class ActionListenerInstaller { // 处理Annotation的方法,其中obj是包含Annotation的对象 public static void processAnnotations(Object obj) { try { // 获取obj对象的类 Class cl = obj.getClass(); // 获取指定obj对象的所有成员变量,并遍历每个成员变量 for (Field f : cl.getDeclaredFields()) { // 将该成员变量设置成可自由访问。 f.setAccessible(true); // 获取该成员变量上ActionListenerFor类型的Annotation ActionListenerFor a = f.getAnnotation(ActionListenerFor.class); // 获取成员变量f的值 Object fObj = f.get(obj); // 如果f是AbstractButton的实例,且a不为null if (a != null && fObj != null && fObj instanceof AbstractButton) { // 获取a注解里的listner元数据(它是一个监听器类) Class<? extends ActionListener> listenerClazz = a .listener(); // 使用反射来创建listner类的对象 ActionListener al = listenerClazz.newInstance(); AbstractButton ab = (AbstractButton) fObj; // 为ab按钮添加事件监听器 ab.addActionListener(al); } } } catch (Exception e) { e.printStackTrace(); } } } public class AnnotationTest { private JFrame mainWin = new JFrame("使用注解绑定事件监听器"); // 使用Annotation为ok按钮绑定事件监听器 @ActionListenerFor(listener = OkListener.class) private JButton ok = new JButton("确定"); // 使用Annotation为cancel按钮绑定事件监听器 @ActionListenerFor(listener = CancelListener.class) private JButton cancel = new JButton("取消"); public void init() { // 初始化界面的方法 JPanel jp = new JPanel(); jp.add(ok); jp.add(cancel); mainWin.add(jp); ActionListenerInstaller.processAnnotations(this); // ① mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainWin.pack(); mainWin.setVisible(true); } public static void main(String[] args) { new AnnotationTest().init(); } } // 定义ok按钮的事件监听器实现类 class OkListener implements ActionListener { public void actionPerformed(ActionEvent evt) { JOptionPane.showMessageDialog(null, "单击了确认按钮"); } } // 定义cancel按钮的事件监听器实现类 class CancelListener implements ActionListener { public void actionPerformed(ActionEvent evt) { JOptionPane.showMessageDialog(null, "单击了取消按钮"); } }
// 指定该注解信息会保留到运行时 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(FkTags.class) public @interface FkTag { // 为该注解定义2个成员变量 String name() default "疯狂软件"; int age(); } // 指定该注解信息会保留到运行时 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FkTags { // 定义value成员变量,该成员变量可接受多个@FkTag注解 FkTag[] value(); } @FkTag(age = 5) @FkTag(name = "疯狂Java", age = 9) // @FkTags({@FkTag(age=5), // @FkTag(name="疯狂Java" , age=9)}) public class FkTagTest { public static void main(String[] args) { Class<FkTagTest> clazz = FkTagTest.class; /* * 使用Java 8新增的getDeclaredAnnotationsByType()方法获取 修饰FkTagTest类的多个@FkTag注解 */ FkTag[] tags = clazz.getDeclaredAnnotationsByType(FkTag.class); // 遍历修饰FkTagTest类的多个@FkTag注解 for (FkTag tag : tags) { System.out.println(tag.name() + "-->" + tag.age()); } /* * 使用传统的getDeclaredAnnotation()方法获取 修饰FkTagTest类的@FkTags注解 */ FkTags container = clazz.getDeclaredAnnotation(FkTags.class); System.out.println(container); } } // 定义一个简单的Type Annotation,不带任何成员变量 @Target(ElementType.TYPE_USE) @interface NotNull{} // 定义类时使用Type Annotation @NotNull public class TypeAnnotationTest implements @NotNull /* implements时使用Type Annotation */ Serializable { // 方法形参中使用Type Annotation public static void main(@NotNull String[] args) // throws时使用Type Annotation throws @NotNull FileNotFoundException { Object obj = "fkjava.org"; // 强制类型转换时使用Type Annotation String str = (@NotNull String)obj; // 创建对象时使用Type Annotation Object win = new @NotNull JFrame("疯狂软件"); } // 泛型中使用Type Annotation public void foo(List<@NotNull String> info){} } @SupportedSourceVersion(SourceVersion.RELEASE_8) // 指定可处理@Persistent、@Id、@Property三个Annotation @SupportedAnnotationTypes({ "Persistent", "Id", "Property" }) public class HibernateAnnotationProcessor extends AbstractProcessor { // 循环处理每个需要处理的程序对象 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // 定义一个文件输出流,用于生成额外的文件 PrintStream ps = null; try { // 遍历每个被@Persistent修饰的class文件 for (Element t : roundEnv .getElementsAnnotatedWith(Persistent.class)) { // 获取正在处理的类名 Name clazzName = t.getSimpleName(); // 获取类定义前的@Persistent Annotation Persistent per = t.getAnnotation(Persistent.class); // 创建文件输出流 ps = new PrintStream(new FileOutputStream(clazzName + ".hbm.xml")); // 执行输出 ps.println("<?xml version=\"1.0\"?>"); ps.println("<!DOCTYPE hibernate-mapping PUBLIC"); ps.println(" \"-//Hibernate/Hibernate " + "Mapping DTD 3.0//EN\""); ps.println(" \"http://www.hibernate.org/dtd/" + "hibernate-mapping-3.0.dtd\">"); ps.println("<hibernate-mapping>"); ps.print(" <class name=\"" + t); // 输出per的table()的值 ps.println("\" table=\"" + per.table() + "\">"); for (Element f : t.getEnclosedElements()) { // 只处理成员变量上的Annotation if (f.getKind() == ElementKind.FIELD) // ① { // 获取成员变量定义前的@Id Annotation Id id = f.getAnnotation(Id.class); // ② // 当@Id Annotation存在时输出<id.../>元素 if (id != null) { ps.println(" <id name=\"" + f.getSimpleName() + "\" column=\"" + id.column() + "\" type=\"" + id.type() + "\">"); ps.println(" <generator class=\"" + id.generator() + "\"/>"); ps.println(" </id>"); } // 获取成员变量定义前的@Property Annotation Property p = f.getAnnotation(Property.class); // ③ // 当@Property Annotation存在时输出<property.../>元素 if (p != null) { ps.println(" <property name=\"" + f.getSimpleName() + "\" column=\"" + p.column() + "\" type=\"" + p.type() + "\"/>"); } } } ps.println(" </class>"); ps.println("</hibernate-mapping>"); } } catch (Exception ex) { ex.printStackTrace(); } finally { if (ps != null) { try { ps.close(); } catch (Exception ex) { ex.printStackTrace(); } } } return true; } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) @Documented public @interface Id { String column(); String type(); String generator(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) @Documented public @interface Persistent { String table(); } @Persistent(table = "person_inf") public class Person { @Id(column = "person_id", type = "integer", generator = "identity") private int id; @Property(column = "person_name", type = "string") private String name; @Property(column = "person_age", type = "integer") private int age; // 无参数的构造器 public Person() { } // 初始化全部成员变量的构造器 public Person(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } // 下面省略所有成员变量的setter和getter方法 // id的setter和getter方法 public void setId(int id) { this.id = id; } public int getId() { return this.id; } // name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } // age的setter和getter方法 public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) @Documented public @interface Property { String column(); String type(); }
|