zoukankan      html  css  js  c++  java
  • 【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();
        }
    }
    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) + "个方法,其中:
    " + "失败了:"
                    + failed + "个,
    " + "成功了:" + 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
  • 相关阅读:
    Android 定制RadioButton样式
    TabActivity的不同实现
    android源码的目录
    让我们一起来做最漂亮的Android界面
    【Android布局】在程序中设置android:gravity 和 android:layout_Gravity属性
    iPhone iPad 各种控件默认高度
    互联网的的一些历史资料收集
    Android vs iPhone icon设计指南
    android获取手机cpu是单核还是多核的方法
    前端必读:浏览器内部工作原理
  • 原文地址:https://www.cnblogs.com/pipi-changing/p/5428517.html
Copyright © 2011-2022 走看看