一. 什么是注解
Annotation是JDK1.5开始引入的新技术
Annotation的作用:
- 不是程序本身,可以对程序作出解释。这一点与注释没什么区别。注释是给程序猿看的,注解是给机器看的。
- 可以被其他程序(比如编译器等)读取。注解信息处理流程,是注解和注释的重要区别。如果没有注解信息处理流程,则注解毫无意义。
Annotation的格式:
- 注解是以“@注释名”在代码中存在的,如:@Test
- 还可以添加一些参数信息。如:String value default "";
二. 内置注解:
1. @Override
2. @Deprecated
3. @SuppressWarnings:
- deprecation:使用了过时的方法或类的警告
- unchecked:执行了未检查的转换时的警告,如果使用集合时未指定泛型。
- fallthrough:当使用switch语句使用时发生case穿透
- path:在类路径、源文件路径等中有不存在路径的警告
- serial:当在序列化的类上确山serialVersionUID定义时的警告
- finally:任何finally子句不能完成时的警告
- all:以上所有情况
4. @SafeVarargs:JDK1.7后新增,用于压制泛,堆内存污染。
5. @FunctionalInterface:JDK1.8后增加,指定是函数式编程接口
三、元注解
1. @Retention:保留期
RetentionPolicy.SOURCE:源码
RetentionPolicy.CLASS:class文件
RetentionPolicy.RUNTIME:运行时
2. @Target:目标
ElementType.ANNOTATION_TYPE:类型成员(方法、构造方法、成员变量、枚举值)
ElementType.CONSTRUCTOR:类型成员(方法、构造方法、成员变量、枚举值)
ElementType.FIELD:类型成员(方法、构造方法、成员变量、枚举值)
ElementType.LOCAL_VARIBALE:方法参数、本地变量
ElementType.METHOD:类型成员(方法、构造方法、成员变量、枚举值)
ElementType.PACKAGE:包
ElementType.PARAMETER:方法参数、本地变量
ElementType.TYPE:类、接口、枚举、Annotation
3. @Documented
4. @Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。 说的比较抽象。代码来解释。
注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
/* * @Inherited测试*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
}
@Test
public class A {
}
public class B extends A {
}
5. @Repeatable:JDK1.8新增元注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
public @interface Person {
String role() default "";
}
/**
* 测试多重角色,JDK1.8后新特性
*/
@Person(role = "coder")
@Person(role = "artist")
@Person(role = "singging")
public class SuperMan {
}
/**
* 测试JDK1.8后的新增元注解
*/
public class RetentionTest {
public static void main(String[] args) throws ClassNotFoundException {
//获取class对象,下获取注解
Class<?> clazz = Class.forName("com.dayDayUp.annotation.retentionAnno.SuperMan");
System.out.println("=====================是否是注解========================");
boolean flag1 = clazz.isAnnotationPresent(Person.class);//是否是注解
boolean flag2 = clazz.isAnnotationPresent(Persons.class);
System.out.println(flag1);
System.out.println(flag2);
System.out.println("=====================是否是注解========================");
boolean c1 = clazz.isAnnotation();
boolean c2 = Person.class.isAnnotation();
System.out.println(c1);
System.out.println(c2);
System.out.println("=====================clazz.getAnnotation()========================");
Person person = clazz.getAnnotation(Person.class);
Persons persons = clazz.getAnnotation(Persons.class);
//String role = person.role();
//System.out.println("person:" + role);
//Class<? extends Annotation> ca1 = person.annotationType();
//System.out.println("person:" + ca1);
//Person[] personArr = persons.value();
//System.out.println("persons:" + personArr);
//for (Person p1 : personArr) {
// System.out.println(p1.role());
// System.out.println(p1.annotationType());
//}
//System.out.println("persons:" +persons.annotationType());
System.out.println(person);
System.out.println(persons);
System.out.println("=====================clazz.getAnnotations()========================");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation1 : annotations) {
System.out.println(annotation1.annotationType());
}
}
}
四. 注解的分类
根据注解参数的个数,我们可以将注解分为三类:
- 标记注解:一个没有成员定义的Annotation类型被称为标记注解。这种Annotation类型仅使用自身的存在与否来为我们提供信息。比如后面的系统注解@Override;
- 单值注解
- 完整注解
根据注解使用方法和用途,我们可以将Annotation分为三类:
- JDK内置系统注解
- 元注解
- 自定义注解
五. 注解与反射
获取Class对象:Class<?> clazz = Class.forName("com.dayDayUp.annotation.retentionAnno.SuperMan");
判断Class对象是否是注解:boolean flag2 = clazz.isAnnotationPresent(Persons.class);
判断Class对象是否是注解:boolean c2 = Person.class.isAnnotation();
获取指定注解:**``Person person = clazz.getAnnotation(Person.class);
获取所有注解:Annotation[] annotations = clazz.getAnnotations();
获取注解类型:annotation1.annotationType();
六. 自定义注解
@Target(value =ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StuFiled {
String cloumnName();
String type();
int length();
}
@StuTable("t_student")
public class Student {
@StuFiled(cloumnName="id" ,type = "int" ,length = 6)
private int id;
@StuFiled(cloumnName="id" ,type = "String" ,length = 18)
private String name;
@StuFiled(cloumnName="id" ,type = "String" ,length = 2)
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* @Description: 使用反射读取注解的信息,模拟处理注解信息的流程
*/
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class<?> clazz = Class.forName("tf56.partyManage.study.annotation.Student");
//获取这个类所有的有效注解注解(获得了类上的注解)
//@tf56.partyManage.study.annotation.StuTable(value=t_student)
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations){
System.out.println(annotation);
}
//获取类的指定的注解
StuTable st = clazz.getAnnotation(StuTable.class);
System.out.println(st);
System.out.println(st.value());
/**
* 获取类的属性的注解
* 1、首先通过反射获取file,属性
* 2、通过file获取对应属性上的注解
* 2、获取注解的值
* 反射
*/
Field f = clazz.getDeclaredField("name");
System.out.println(f);
StuFiled sf = f.getAnnotation(StuFiled.class);
System.out.println(sf.cloumnName());
System.out.println(sf.type());
System.out.println(sf.length());
}
}
#案例二
public class NoBug {
@Jiecha
public void suanShu(){
System.out.println("1234567890");
}
@Jiecha
public void jiafa(){
System.out.println("1+1="+1+1);
}
@Jiecha
public void jiefa(){
System.out.println("1-1="+(1-1));
}
@Jiecha
public void chengfa(){
System.out.println("3 x 5="+ 3*5);
}
@Jiecha
public void chufa(){
System.out.println("6 / 0="+ 6 / 0);
}
public void ziwojieshao(){
System.out.println("我写的程序没有 bug!");
}
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestTool {
public static void main(String[] args) {
// TODO Auto-generated method stub
NoBug testobj = new NoBug();
Class clazz = testobj.getClass();
Method[] method = clazz.getDeclaredMethods();
//用来记录测试产生的 log 信息
StringBuilder log = new StringBuilder();
// 记录异常的次数
int errornum = 0;
for ( Method m: method ) {
// 只有被 @Jiecha 标注过的方法才进行测试
if ( m.isAnnotationPresent( Jiecha.class )) {
try {
m.setAccessible(true);
m.invoke(testobj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
//e.printStackTrace();
errornum++;
log.append(m.getName());
log.append(" ");
log.append("has error:");
log.append("\n\r caused by ");
//记录测试过程中,发生的异常的名称
log.append(e.getCause().getClass().getSimpleName());
log.append("\n\r");
//记录测试过程中,发生的异常的具体信息
log.append(e.getCause().getMessage());
log.append("\n\r");
}
}
}
log.append(clazz.getSimpleName());
log.append(" has ");
log.append(errornum);
log.append(" error.");
// 生成测试报告
System.out.println(log.toString());
}
}
测试的结果是:
1234567890
1+1=11
1-1=0
3 x 5=15
chufa has error:
caused by ArithmeticException
/ by zero
NoBug has 1 error.
网友评论