Annotationjava
5個基本的Annotation程序員
•@Override數組
•@Deprecatedapp
•@SuppressWarningsdom
•@SafeVarargside
•@FunctionalInterface工具
使用自定義Annotation測試
•使用@interface定義Annotationui •使用Annotation修飾程序中的類、方法、變量、接口等定義,一般咱們會把Annotation放在全部修飾符以前。this •定義帶成員變量的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(); } |