【13-Annotation】

 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();
    }
}
View Code
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);
    }
}
View Code
public class ErrorUtilsTest {
    public static void main(String[] args) {
        ErrorUtils.faultyMethod(Arrays.asList("Hello!"),
                Arrays.asList("World!"));
    }
}
View Code
public class Fruit {
    public void info() {
        System.out.println("水果的info方法...");
    }
}

class Apple extends Fruit {
    // 使用@Override指定下面方法必須重寫父類方法
    @Override
    public void inf0() {
        System.out.println("蘋果重寫水果的info方法...");
    }
}
View Code
@FunctionalInterface
public interface FunInterface
{
    static void foo()
    {
        System.out.println("foo類方法");
    }
    default void bar()
    {
        System.out.println("bar默認方法");
    }
    void test(); // 只定義一個抽象方法

    void abc();
}
View Code
// 關閉整個類裏的編譯器警告
@SuppressWarnings(value = "unchecked")
public class SuppressWarningsTest {
    public static void main(String[] args) {
        List<String> myList = new ArrayList(); //
    }
}
View Code

 


 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Inheritable {
}
View Code
// 使用@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));
    }
}
View Code
public class MyTest {
    // 使用@Test修飾info方法
    @Testable
    public void info() {
        System.out.println("info方法...");
    }
}
View Code
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
// 定義Testable Annotation將被javadoc工具提取
@Documented
public @interface Testable {
}
View Code

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() {
    }
}
View 01
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 + "個!");
    }
}
View 01
public class RunTests {
    public static void main(String[] args) throws Exception {
        // 處理MyTest類
        ProcessorTest.process("MyTest");
    }
}
View 01
// 使用JDK的元數據Annotation:Retention
@Retention(RetentionPolicy.RUNTIME)
// 使用JDK的元數據Annotation:Target
@Target(ElementType.METHOD)
// 定義一個標記註解,不包含任何成員變量,即不可傳入元數據
public @interface Testable {
}
View 01

 

 

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
    // 定義一個成員變量,用於設置元數據
    // 該listener成員變量用於保存監聽器實現類
    Class<? extends ActionListener> listener();
}
View 02
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();
        }
    }
}
View 02
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, "單擊了取消按鈕");
    }
}
View 02

 

 


// 指定該註解信息會保留到運行時
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(FkTags.class)
public @interface FkTag {
    // 爲該註解定義2個成員變量
    String name() default "瘋狂軟件";

    int age();
}
View Code
// 指定該註解信息會保留到運行時
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FkTags {
    // 定義value成員變量,該成員變量可接受多個@FkTag註解
    FkTag[] value();
}
View Code
@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);
    }
}
View Code
// 定義一個簡單的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){}
}
View Code

@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;
    }
}
View Code
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Id {
    String column();

    String type();

    String generator();
}
View Code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Persistent {
    String table();
}
View Code
@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;
    }

}
View Code
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Property {
    String column();

    String type();
}
View Code
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息