一. 什么是注解
Annotation是JDK1.5開始引入的新技術(shù)
Annotation的作用:
- 不是程序本身,可以對程序作出解釋。這一點與注釋沒什么區(qū)別。注釋是給程序猿看的,注解是給機器看的箫津。
- 可以被其他程序(比如編譯器等)讀取。注解信息處理流程宰啦,是注解和注釋的重要區(qū)別苏遥。如果沒有注解信息處理流程,則注解毫無意義绑莺。
Annotation的格式:
- 注解是以“@注釋名”在代碼中存在的暖眼,如:@Test
- 還可以添加一些參數(shù)信息。如:String value default "";
二. 內(nèi)置注解:
1. @Override
2. @Deprecated
3. @SuppressWarnings:
- deprecation:使用了過時的方法或類的警告
- unchecked:執(zhí)行了未檢查的轉(zhuǎn)換時的警告纺裁,如果使用集合時未指定泛型诫肠。
- fallthrough:當(dāng)使用switch語句使用時發(fā)生case穿透
- path:在類路徑、源文件路徑等中有不存在路徑的警告
- serial:當(dāng)在序列化的類上確山serialVersionUID定義時的警告
- finally:任何finally子句不能完成時的警告
- all:以上所有情況
4. @SafeVarargs:JDK1.7后新增欺缘,用于壓制泛栋豫,堆內(nèi)存污染。
5. @FunctionalInterface:JDK1.8后增加谚殊,指定是函數(shù)式編程接口
三丧鸯、元注解
1. @Retention:保留期
RetentionPolicy.SOURCE:源碼
RetentionPolicy.CLASS:class文件
RetentionPolicy.RUNTIME:運行時
2. @Target:目標(biāo)
ElementType.ANNOTATION_TYPE:類型成員(方法、構(gòu)造方法嫩絮、成員變量丛肢、枚舉值)
ElementType.CONSTRUCTOR:類型成員(方法、構(gòu)造方法剿干、成員變量蜂怎、枚舉值)
ElementType.FIELD:類型成員(方法、構(gòu)造方法置尔、成員變量杠步、枚舉值)
ElementType.LOCAL_VARIBALE:方法參數(shù)、本地變量
ElementType.METHOD:類型成員(方法榜轿、構(gòu)造方法幽歼、成員變量、枚舉值)
ElementType.PACKAGE:包
ElementType.PARAMETER:方法參數(shù)谬盐、本地變量
ElementType.TYPE:類甸私、接口、枚舉飞傀、Annotation
3. @Documented
4. @Inherited
Inherited 是繼承的意思颠蕴,但是它并不是說注解本身可以繼承泣刹,而是說如果一個超類被 @Inherited 注解過的注解進(jìn)行注解的話助析,那么如果它的子類沒有被任何注解應(yīng)用的話犀被,那么這個子類就繼承了超類的注解。 說的比較抽象外冀。代碼來解釋寡键。
注解 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());
}
}
}
四. 注解的分類
根據(jù)注解參數(shù)的個數(shù)藕畔,我們可以將注解分為三類:
- 標(biāo)記注解:一個沒有成員定義的Annotation類型被稱為標(biāo)記注解。這種Annotation類型僅使用自身的存在與否來為我們提供信息庄拇。比如后面的系統(tǒng)注解@Override;
- 單值注解
- 完整注解
根據(jù)注解使用方法和用途注服,我們可以將Annotation分為三類:
- JDK內(nèi)置系統(tǒng)注解
- 元注解
- 自定義注解
五. 注解與反射
獲取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獲取對應(yīng)屬性上的注解
* 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();
//用來記錄測試產(chǎn)生的 log 信息
StringBuilder log = new StringBuilder();
// 記錄異常的次數(shù)
int errornum = 0;
for ( Method m: method ) {
// 只有被 @Jiecha 標(biāo)注過的方法才進(jìn)行測試
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 ");
//記錄測試過程中辜御,發(fā)生的異常的名稱
log.append(e.getCause().getClass().getSimpleName());
log.append("\n\r");
//記錄測試過程中,發(fā)生的異常的具體信息
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());
}
}
測試的結(jié)果是:
1234567890
1+1=11
1-1=0
3 x 5=15
chufa has error:
caused by ArithmeticException
/ by zero
NoBug has 1 error.