Java :Annotation(注释)
来源:互联网 发布:阅面科技 知乎 编辑:程序博客网 时间:2024/05/16 13:41
Java :Annotation(注释)
本文地址:http://blog.csdn.net/shanglianlm/article/details/50350274
1 基本 Annotation
三个基本的 Annotation 如下:
- @Override
- @Deprecated
- @SuppressWarnings
JDK 提供的三个基本 Annotation 都定义在 java.lang 包下。
1-1 限定重写父类方法:@Override
public class Fruit{ public void info() { System.out.println("水果的info方法..."); }}class Apple extends Fruit{ // 使用@Override指定下面方法必须重写父类方法 @Override public void info() { System.out.println("苹果重写水果的info方法..."); }}
1-2 标示已过时:@Deprecated
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(); }}
1-3 抑制编译器警告:@SuppressWarnings
// 关闭整个类里的编译器警告@SuppressWarnings(value="unchecked")public class SuppressWarningsTest{ public static void main(String[] args) { List<String> myList = new ArrayList(); }}
2 自定义 Annotation
2-1 定义 Annotation
// 定义一个简单的 Annotation 类型public @interface Test{}
修饰类
// 使用 @Test 修饰类定义@Testpublic class MyClass{ ...}
修饰方法
public class MyClass{ // 使用 @Test 修饰方法 @Test public void info() { ... } }
添加成员变量
public @interface MyTag{ // 定义了两个成员变量的 Annotation String name(); int age();}
使用
public class Test{ // 使用带成员变量的 Annotation 时,需要为成员变量赋值 @MyTag(name="xx", age=6) public void info() { ... }}
public @interface MyTag{ //使用 default 为两个成员变量指定初始值 String name() default "yeeku"; int age() default 32;}
使用
public class Test{ // @MyTag public void info() { ... }}
2-2 提取 Annotation 的信息
// 获取 Test 类的 info 方法的所有注释Annotation [] aArray = Class.forName("Test").getMethod("info").getAnnotations();// 遍历所有注释for(Annotation an:aArray){ System.out.println(an);}
// 获取 tt 对象的 info 方法所包含的所有注释Annotation [] annotation = tt.getClass().getMethod("info").getAnnotations();// 遍历每个注释对象for(Annotation tag:annotation){ // 如果 tag 注释是 MyTag1 类型 if(tag instanceof MyTag1) { System.out.println("Tag is: " + tag); // 将 tag 强制类型转换为 MyTag1, 并调用 tag 对象的 method1 和 method2 两个方法 System.out.println("tag.name(): " + ((MyTag1)tag).method1()); System.out.println("tag.age(): " + ((MyTag1)tag).method2()); } // 如果 tag 注释是 MyTag2 类型 if(tag instanceof MyTag2) { System.out.println("Tag is: " + tag); // 将 tag 强制类型转换为 MyTag2, 并调用 tag 对象的 method1 和 method2 两个方法 System.out.println("tag.name(): " + ((MyTag2)tag).method1()); System.out.println("tag.age(): " + ((MyTag2)tag).method2()); }}
2-3 使用 Annotation 的例子
两个例子
1. 没有任何成员变量的 Annotation,,用于标识哪些方法是可测试的。
Testable.java
//使用JDK的元数据Annotation:Retention@Retention(RetentionPolicy.RUNTIME)// 使用JDK的元数据Annotation:Target@Target(ElementType.METHOD)// 定义一个标记注释,不包含任何成员变量,即不可传入元数据public @interface Testable {}
MyTest.java
public class MyTest{ // 使用@Testable标记注释指定该方法是可测试的 @Testable public static void m1() { } public static void m2() { } // 使用@Testable标记注释指定该方法是可测试的 @Testable public static void m3() { throw new RuntimeException("Boom"); } public static void m4() { } // 使用@Testable标记注释指定该方法是可测试的 @Testable public static void m5() { } public static void m6() { } // 使用@Testable标记注释指定该方法是可测试的 @Testable public static void m7() { throw new RuntimeException("Crash"); } public static void m8() { }}
ProcessorTest.java
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++; } } } //统计测试结果 System.out.println("共运行了:" + (passed + failed) + "个方法,其中:\n" + "失败了:" + failed + "个,\n" + "成功了:" + passed + "个!"); }}
RunTests.java
public class RunTests{ public static void main(String[] args) throws Exception { //处理MyTest类 ProcessorTest.process("MyTest"); }}
运行结果:
- 通过 ActionListenerFor Annotation 来为程序中的按钮绑定事件监听器
ActionListenerFor.java
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface ActionListenerFor { //定义一个成员变量,用于设置元数据 //该listener成员变量用于保存监听器实现类 Class<? extends ActionListener> listener(); }
AnnotationTest.java
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 , "单击了取消按钮"); }}
ActionListenerInstaller.java
public class ActionListenerInstaller{ // 处理Annotation的方法,其中obj是包含Annotation的对象 public static void processAnnotations(Object obj) { try { // 获取obj对象的类 Class cl = obj.getClass(); // 获取指定obj对象的所有Field,并遍历每个Field for (Field f : cl.getDeclaredFields()) { // 将指定Field设置成可自由访问。 f.setAccessible(true); // 获取指定Field上ActionListenerFor类型的Annotation ActionListenerFor a = f.getAnnotation(ActionListenerFor.class); // 获取f Field实际对应的对象 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(); } }}
运行结果:
3 JDK 的元 Annotation
3-1 使用 @Retention
// 定义下面的 Testable Annotation 的保留到运行时@Retention(value = RetentionPoicy.RUNTIME)public @interface Testable{}
或
// 定义下面的 Testable Annotation 将被编译器直接丢弃@Retention(RetentionPoicy.SOURCE)public @interface Testable{}
3-2 使用 @Target
@Target(ElementType.FIELD)public @interface ActionListenerFor{}
3-3 使用 @Documented
Testable.java
// 定义下面的 Testable Annotation 将被编译器直接丢弃@Retention(RetentionPoicy.RUNTIME)@Target(ElementType.METHOD)// 定义 Testable Annotation 将被 javadoc 工具提取@Documentedpublic @interface Testable{}
MyTest.java
public class MyTest{ // 使用 @Test 修饰 info 方法 @Testable public void info() { System.out.println("info 方法..."); }}
3-4 使用 @Inherited
Inheritable.java
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface Inheritable{}
TestInheritable.java
// 使用@Inheritable修饰的Base类@Inheritableclass 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)); }}
4 使用 APT 处理 Annotation
Persistent.java
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)@Documentedpublic @interface Persistent{ String table();}
IdProperty.java
@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)@Documentedpublic @interface IdProperty{ String column(); String type(); String generator();}
Property.java
@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)@Documentedpublic @interface Property{ String column(); String type();}
Person.java
@Persistent(table="person_inf")public class Person{ @IdProperty(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; } // 下面省略各Field的setter和getter方法 ... }
为上面三个 Annotation 提供一个 Annotation 处理器,该处理器的功能是根据注释来生成一个 Hibernate 映射文件。
HibernateAnnotationProcessor.java
@SupportedSourceVersion(SourceVersion.RELEASE_7)// 指定可处理@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()) { // 只处理Field上的Annotation if (f.getKind() == ElementKind.FIELD) //① { // 获取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>"); } // 获取Field定义前的@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; }}
HibernateAnnotationFactory.java
public class HibernateAnnotaionFactory implements AnnotationProcessorFactory{ // 所有支持的注释类型 public Collection<String> supportedAnnotationTypes() { return Arrays.asList("Property", "IdProperty", "Persistent"); } // 返回所有支持的选项 public Collection<String> supportedOption() { return Arrays.asList(new String[0]); } // 返回 Annotation 处理器 public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) { return new HibernateAnnotationProcessor(env); }}
提供上述工厂后,就可以使用 APT 工具来处理上面的 源文件,并据此生成一份 xml 文件。
APT 工具位于 JDK 安装路径的 bin 目录下。
rem HibernateAnnotationFactory Person.java Annotationapt -factory HibernateAnnotationFactory Person.java
生成的 Person.hbm.xml 文件
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping> <class name="Person" table="person_inf"> <id name="id" column="person_id" type="integer"> <generator class="identity"/> </id> <property name="name" column="person_name" type="string"/> <property name="age" column="person_age" type="integer"/> </class></hibernate-mapping>
- Java注释(Annotation)
- Java注释(Annotation)
- Java :Annotation(注释)
- 16. Java Annotation(注释)
- java的Annotation(注释)
- Java-----12、Annotation(注释)
- Java Annotation注释语法(元注释)
- Java基础(六)----注释 annotation
- Java Annotation注释语法
- Java Annotation注释语法
- java annotation 注释 简介
- Java注释(Annotation)详解
- Java注释(Annotation)详解
- Annotation:java注释
- Java Annotation注释语法
- Java注释Annotation
- Java注释Annotation
- Java注释(Annotation)详解
- Linux USB驱动分析之USB2.0协议分析
- Request&Response编程
- Duilib界面布局文件XML学习-XML文件简介
- 两个框架之间的数据类型转换,需要桥接技术
- OC学习 第七节 手动内存管理
- Java :Annotation(注释)
- Django - “no module named django.core.management”
- 两种方式的i2c设备驱动的编写方法
- 臭石头的使用(Cornerstone),冲突的解决
- 进制转换函数
- 常用的电压基准芯片
- K中心点算法(K-medoids)
- Eclipse快捷键
- <LeetCode OJ> 8. String to Integer (atoi)