【13-Annotation】

时间:2022-12-05 17:55:33

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