【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() {
    }
}

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();
}

// 指定该注解信息会保留到运行时
@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();
}

时间: 2024-10-22 01:21:27

【13-Annotation】的相关文章

友人与友情【诗词13首】

友人与友情[13首] 八月八日读友人来信 葡萄葵花静掩门,卧看晚霞染天痕. 挂冠日日嫌才拙,思友年年盼北鸿. 策马有心鞭已折,捎书无耐日全昏. 虽从昨夜长岭会,却是黄粱饭又冷. [注]友人家在东北长岭县,故有“长岭会”之句. 答友人 川地蜀葵一笑何,灵州见晚恨蹉跎. 春风共度时犹少,燕蓟同窗话不多. 万里风云山河壮,七寸管毫日月歌. 精神无限攀东嶽,学比青松扶蔓萝.     [注]友人,四川盐亭人,善诗词. 忆昔(西安旅次)  忆昔长安小饮时,朔风吹裔冷丝丝. 一杯水问君何干?半月风劳远送离.

第 13 章 装饰模式【Decorator Pattern】

以下内容出自:<<24种设计模式介绍与6大设计原则>> Ladies and gentlemen,May I get your attention,Please?,Now I’m going to talk about decoratorpattern.装饰模式在中国使用的那实在是多,中国的文化是中庸文化,说话或做事情都不能太直接,需要有技巧的,比如说话吧,你要批评一个人,你不能一上来就说你这个做的不对,那个做的不对,你要先肯定他的成绩,表扬一下优点,然后再指出瑕疵,指出错误的地方

【UER #1】[UOJ#12]猜数 [UOJ#13]跳蚤OS [UOJ#14]DZY Loves Graph

[UOJ#12][UER #1]猜数 试题描述 这一天,小Y.小D.小C正在愉快地玩耍. 小Y是个数学家,他一拍脑袋冒出了一个神奇的完全平方数 n. 小D是个机灵鬼,很快从小Y嘴里套出了 n的值.然后在脑内把 n写成了 a×b的形式.其中 a,b 都是正整数. 小C是个八卦狂,他发现小D从小Y那里获知了神奇的东西,于是死缠烂打追问小D.最后小D说道:“我可以告诉你正整数 g和 l的值,我保证 ab=gl=n且 a,b都是 g 的倍数.但是 a,b 我可不能告诉你.” 这可急坏了小C.他决定退而求

LeetCode:罗马数字转整数【13】

LeetCode:罗马数字转整数[13] 题目描述 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并列的 1.12 写做 XII ,即为 X + II . 27 写做  XXVII, 即为 XX + V + II . 通常情况下,罗马数字中小的数字在大的数字的右边.但也存在特例,例如 4 不写做 IIII,而是 IV.数字 1 在数字 5 的左边

【小白的CFD之旅】13 敲门实例【续3】

接上文[小白的CFD之旅]12 敲门实例[续2] 4 Results4.1 计算监测图形4.2 Graphics4.2.1 壁面温度分布4.2.2 创建截面4.2.3 显示截面物理量4.2.4 Pathline显示4.3 Plots 4 Results 计算后处理. 4.1 计算监测图形 残差曲线 计算监测得到的残差曲线如下图所示. 图中残差曲线显示计算在迭代120步左右达到收敛,表现为残差曲线降低至设置的残差标准以下,默认残差标准为10?310?3 入口压力监测图 两个入口压力监测图如下图所示

【VBA编程】13.Workbook对象的事件

Workbook事件用于响应对Workbook对象所进行的操作. [BeforeClose事件] BforeClose事件用于响应窗口关闭的操作 在工程资源器中,双击"ThisWorkbook"对象,弹出"ThisWorkbook"窗口,并且选择Workbook,BeforeClose 并在窗口中写下如下代码:[代码区域] Private Sub Workbook_BeforeClose(Cancel As Boolean) If ThisWorkbook.Save

【jackson 异常】com.fasterxml.jackson.databind.JsonMappingException异常处理

项目中,父层是Gene.java[基因实体]  子层是Corlib.java[文集库实体],一种基因对用多个文集库文章 但是在查询文集库这个实体的时候报错:[com.fasterxml.jackson.databind.JsonMappingException] 1 com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassis

【j2ee spring】12、整合SSH框架(终结版)

[j2ee spring]12.整合SSH框架(终结版) 最后,我们把整个项目的截图,代码发一下,大家不想下载那个项目的话,可以在这里看到所有的代码(因为那个项目需要一个下载积分,真不多= =,我觉得我搞了那么久,收点积分应该不过分吧...嘿嘿) 这里,我尽量用截图来搞,免得复制粘贴,怪烦的 一.项目整体截图 二.开始全部代码 Person.java Person.hbm.xml PersonService.java package cn.cutter_point.service; import

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

【 js 基础 】Javascript “继承”

是时候写一写 "继承"了,为什么加引号,因为当你阅读完这篇文章,你会知道,说是 继承 其实是不准确的. 一.类1.传统的面向类的语言中的类:类/继承 描述了一种代码的组织结构形式.举个例子:"汽车"可以被看作是"交通工具"的一种特例.我们可以定义一个 Vehicle 类和一个 Car 类来对这种关系进行描述.Vehicle 的定义可能包含引擎.载人能力等,也就是 所有交通工具,比如飞机.火车和汽车等都有的通用的功能描述.在对 Car 类进行定义的