Annotation(注解)简单介绍:

注解大家印象最深刻的可能就是JUnit做单元測试,和各种框架里的使用了。

本文主要简介一下注解的用法,下篇文章再深入的研究。

annotation并不直接影响代码语义。可是它可以被看作类似程序的工具或者类库。它会反过来对正在执行的程序语义有所影响。

annotation能够从源文件,class文件或者以在执行时反射的多种方式被读取

java注解系统自带有主要下面几个注解:

Override注解表示子类要重写(override)父类的相应方法

Deprecated注解表示方法是不建议被使用的

Suppress Warnings注解表示抑制警告

怎样自己定义注解:

仅仅须要使用@interface来定义一个注解,比如:

//使用@interface来声明一个注解(实际上是自己主动继承了java.lang.annotation.Annotation接口)
public @interface AnnotationTest {
String value1() default "hello"; //为注解设置String类型的属性Value1,并使用defalutkeyword设置默认值
EnumTest value2(); //设置枚举类型的value2
String[] value3(); //设置数组类型的value3
}

怎样来使用注解呢,例如以下:

@AnnotationTest(value2 = EnumTest.age, value3={""})
public class AnnotationUsage { @AnnotationTest(value1 = "Test", value2 = EnumTest.name, value3={""})
String test; @AnnotationTest(value1 = "Test", value2 = EnumTest.name, value3={""})
public void method(){
System.out.println("usage of Annotation");
}
}

如上,注解能够标注在属性。方法。类上。

须要使用name=value这样的赋值方式为属性赋值,由于value1设置了默认属性,所以能够忽略,假设没有设置默认值则全部的属性都要一一赋值。

另一种特殊情况,假设注解里仅仅定义了一个属性,名字是value,那么能够直接赋值,不须要使用name=value这样的赋值方式。例如以下:

public @interface AnnotationTest {
String value();
} @AnnotationTest("test")
public void method(){
System.out.println("usage of Annotation");
}

修饰注解的“注解”

注解也能够加入注解的“注解”去修饰,经常使用的有下面两个,一个是Retention。一个Target

Retention:

使用Retention必需要提供一个为java.lang.annotation.RetentionPolicy类型的的枚举

RetentionPolicy枚举有下面3个类型:

SOURCE:编译程序时处理完Annotation信息后就完毕任务

CLASS:编译程序将Annotation存储于class文件里,不能够由虚拟机读入

RUNTIME:编译程序将Annotation存储于class文件里。能够由虚拟机读入

用这三种Retention的Prolicy能够决定注解是从源文件。class文件或者以在执行时反射被读取

关于Retention的样例在最后

Target:

使用java.lang.annotation.Target能够定义注解被使用的位置

相同,在使用时要指定一个java.lang.annotation.ElementType的枚举值类型为他的“属性”

ElementType枚举的类型例如以下:

ANNOTATION_TYPE:适用于annotation

CONSTRUCTOR:适用于构造方法

FIELD:适用于field

LOCAL_VARIABLE:适用于局部变量

METHOD:适用于方法

PACKAGE:适用于package

PARAMETER:适用于method上的parameter

TYPE:适用于class,interface,enum

例如以下:定义一个注解MyTarget。设置Target类型为Method来修饰这个注解。这样这个注解仅仅能标注在method的方法上

@Target(ElementType.METHOD)
public @interface MyTarget {
String hello() default "hello";
}
@MyTarget  //这里则会报错,由于他标注在类上面了
public class MyTargetTest {
@MyTarget //标注在方法上不会报错
public void doSomething(){
System.out.println("hello world");
}
}


使用反射调用注解

在下面的类中Class Constructor Field Method Package等类都实现了AnnotatedElement接口
在接口中有下面重要的方法:

getAnnotations(Class annotationType)获取一个指定的annotation类型

getAnnotations() 获取全部的Annotation

getDeclaredAnnotations() 获取声明过的全部Annotation

isAnnotationPresent(Class<? extends Annotation> annotationClass)这个annotation是否出现


通过这些方法,配合反射我们就能够在程序执行时拿到注解的内容了。样例例如以下:
@Retention(RetentionPolicy.RUNTIME)	//定义一个注解。使用Retention标注为RUNTIME
public @interface MyAnnotation {
String hello() default "hello";
String world();
}

该注解被标示为runtime类型,表示该注解最后能够保存在class文件里,并为java虚拟机在执行时读取到

@Retention(RetentionPolicy.CLASS)	//定义一个注解。Retention标注为RUNTIME
public @interface MyAnnotation2 {
String hello() default "hello"; //设置默认值为hello
}

自己定义的还有一个注解Retention标示为class

public class MyTest {
@SuppressWarnings("unchecked") //java自带的注解Retention的policy为SOURCE
@Deprecated //java自带的注解Retention的policy为RUNTIME
@MyAnnotation(Name="Dean", Age="25") //自己定义的注解Retention的policy为RUNTIME
@MyAnnotation2 //自己定义的注解Retention的policy为CLASS
public void TestMethod() {
System.out.println("this is a method");
}
}

定义一个TestMethod方法。给他标示了4个注解。当中2个java自带的,2个我们自己定义的。注解的的Retention属性各不同样。

以下定义一个測试类来验证结果:

public static void main(String[] args) throws Exception {

		MyTest myTest = new MyTest();
//通过反射得到TestMethod方法
Class<MyTest> c = MyTest.class;
Method method = c.getMethod("TestMethod", new Class[]{}); //AnnotatedElement接口中的方法isAnnotationPresent(),推断传入的注解类型是否存在
if (method.isAnnotationPresent(MyAnnotation.class)) {
method.invoke(myTest, new Object[]{});
//AnnotatedElement接口中的方法getAnnotation(),获取传入注解类型的注解
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
//拿到注解中的属性
String name = myAnnotation.Name();
String age = myAnnotation.Age();
System.out.println("name:"+name +" age:"+age);
} System.out.println("-----------------------------------"); //AnnotatedElement接口中的方法getAnnotations(),获取全部注解
Annotation[] annotations = method.getAnnotations();
//循环注解数组打印出注解类型的名字
for (Annotation annotation : annotations) {
System.out.println(annotation.annotationType().getName());
}
}

打印结果为:

this is a method

name:Dean   age:25

-----------------------------------

java.lang.Deprecated

gxy.text.annotation.MyAnnotation

切割线上:介绍了怎样使用AnnotatedElement接口中的方法和反射去调用注解

切割线下:证明了仅仅有定义了Retention的Policy为Runtime的注解才干够被反射读取出来

下一篇文章分析一下在JUnit中反射与注解的使用和原理

最新文章

  1. 高性能IO模型浅析
  2. web前端基础知识 Dom
  3. python复习
  4. Fiddler Tips
  5. 文本模板转换工具包和 ASP.NET MVC
  6. LeetCode Combination Sum III
  7. date 笔记
  8. 更改linux系统时间
  9. QML 语言基础
  10. javascript第三章--引用类型
  11. java IO 类库的基本架构
  12. 【转】Matlab中的括号()[] {}
  13. Cookie&#160;SQL注入
  14. tcp_connect函数
  15. genymotion和adb的解决方法
  16. 20155319 2016-2017-2 《Java程序设计》第八周学习总结
  17. Generative Model 与 Discriminative Model
  18. Freemarker入门
  19. vue+webpack开发(一)
  20. Java GUI编程中AWT/swing/SWT的优缺点

热门文章

  1. Maven项目消除奇怪的红叉
  2. javascript 中 click 和onclick有什么区别呢
  3. zmap zgrab 环境搭建
  4. SQL 数据库函数
  5. win2008服务器asp站点配置要点
  6. Request的Body只能读取一次解决方法
  7. Appium+python自动化14-查看webview上元素(DevTools)【转载】
  8. Ext中点击某个东西弹出框展示
  9. ubuntu 安装TensorFlow
  10. ASP.NET MVC4 MVC 当前上下文中不存在名称“Scripts”