注解是什么
我們?cè)谄綍r(shí)的工作中,可能會(huì)看到形如一下的代碼:
@Entity(tableName = "user")
public class User{
@Id
@Column(name="id")
private long id;
@Column(name="uid")
private String uid;
...
}
這種標(biāo)記在類(lèi)上,方法上,@開(kāi)頭的就叫做注解.
注解的用處
上圖是我們公司ORM框架的一個(gè)entity類(lèi),總所周知,ORM框架與數(shù)據(jù)庫(kù)打交道,最后也要轉(zhuǎn)為SQL語(yǔ)句.比如保存一條記錄,數(shù)據(jù)庫(kù)只接受INSERT INTO USER('id','uid') VALUES('1', 'huangzp')這樣的保存方式,如果當(dāng)我們操作 orm.save(user),這樣的代碼的時(shí)候,實(shí)際上也是將它轉(zhuǎn)成SQL,那么對(duì)象要怎么轉(zhuǎn)成SQL呢?可以看到,要轉(zhuǎn)成SQL,至少要知道表名,字段,那么我們?cè)陬?lèi)中標(biāo)明類(lèi)名和表名及成員變量和字段的對(duì)應(yīng)關(guān)系不就OK了嗎?當(dāng)我們要保存保存數(shù)據(jù)的時(shí)候,通過(guò)反射取得這些注解,然后拼成SQL.完美! 所以注解相當(dāng)于一個(gè)標(biāo)記,我們最后還是得通過(guò)反射等手段獲取這些注解,然后寫(xiě)成我們需要的功能.
定義一個(gè)注解
我們使用一個(gè)類(lèi)的時(shí)候,我們要先去定義一個(gè)類(lèi),比如
public class Cat{}
同樣的,我們要使用一個(gè)注解,同樣也要去定義
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {
//注解元素
String tableName() default "";
//快捷方式,我們?cè)O(shè)置了value的元素的時(shí)候,設(shè)置value的值的時(shí)候,只需要@Entity("haha")而不需要@Entity(value="haha")
String value() default "";
}
- @interface 是聲明一個(gè)注解,就像我們class,enum一樣.
- @Target 是注解修飾范圍的范圍,我們可以看一下ElementType這個(gè)枚舉類(lèi)
public enum ElementType {
/**注解在類(lèi)名,接口名,枚舉名上 */
TYPE,
/** 注解在成員變量上 */
FIELD,
/** 注解在方法名上 */
METHOD,
/** 注解在方法參數(shù)上 */
PARAMETER,
/** 注解在構(gòu)造方法上 */
CONSTRUCTOR,
/** 注解在局部變量 */
LOCAL_VARIABLE,
/** 注解在注解上 */
ANNOTATION_TYPE,
/** 注解在包名上 */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
- @Retention 注解的運(yùn)行時(shí)期
A. SOURCE : 注解將被編譯器丟棄(該類(lèi)型的注解信息只會(huì)保留在源碼里日川,源碼經(jīng)過(guò)編譯后,注解信息會(huì)被丟棄,不會(huì)保留在編譯好的class文件里)
B. CLASS : 注解在class文件中可用,但會(huì)被VM丟棄(該類(lèi)型的注解信息會(huì)保留在源碼里和class文件里,在執(zhí)行的時(shí)候边败,不會(huì)加載到虛擬機(jī)中),請(qǐng)注意,當(dāng)注解未定義Retention值時(shí)噩峦,默認(rèn)值是CLASS,如Java內(nèi)置注解抽兆,@Override识补、@Deprecated、@SuppressWarnning等
C. RUNTIME : 注解信息將在運(yùn)行期(JVM)也保留郊丛,因此可以通過(guò)反射信機(jī)制讀取注解的息(源碼李请、class文件和執(zhí)行的時(shí)候都有注解的信息)瞧筛,如SpringMvc中的@Controller、@Autowired导盅、@RequestMapping等较幌。 - 注解的元素及其類(lèi)型
String name() default "";
在注解名花括號(hào)里的便是注解的元素,它對(duì)應(yīng)的是我們寫(xiě)在@Entity(name="user"),的大括號(hào)里面的東西,除了常見(jiàn)的string和int類(lèi)型,它還可以是以下的幾種類(lèi)型:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Reference{
boolean next() default false;
}
public @interface AnnotationElementDemo {
//枚舉類(lèi)型
enum Status {FIXED,NORMAL};
//聲明枚舉
Status status() default Status.FIXED;
//布爾類(lèi)型
boolean showSupport() default false;
//String類(lèi)型
String name()default "";
//class類(lèi)型
Class<?> testCase() default Void.class;
//注解嵌套
Reference reference() default @Reference(next=true);
//數(shù)組類(lèi)型
long[] value();
}
元注解(@Target(ElementType.ANNOTATION_TYPE))
剛剛介紹的@Target,@Retention便是元注解,元注解負(fù)責(zé)注解其他注解,Java還有@Documented 和 @Inherited 兩個(gè)元注解.
- @Documented 被修飾的注解會(huì)生成到j(luò)avadoc中
- @Inherited 被注解的注解 注解的類(lèi),可以被其他類(lèi)繼承,然后注解的特性會(huì)轉(zhuǎn)移到子類(lèi)上,子類(lèi)Class對(duì)象使用getAnnotations()獲取父類(lèi)被@Inherited修飾的注解
Java內(nèi)置注解(@Retention(RetentionPolicy.RUNTIME))
- @Override:用于標(biāo)明此方法覆蓋了父類(lèi)的方法
- @Deprecated:用于標(biāo)明已經(jīng)過(guò)時(shí)的方法或類(lèi)
- @SuppressWarnnings:用于有選擇的關(guān)閉編譯器對(duì)類(lèi)、方法白翻、成員變量乍炉、變量初始化的警告 比如 :
@SuppressWarnings({"uncheck","deprecation"})
注解與反射
- public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
注解通過(guò)反射獲取。首先可以通過(guò) 對(duì)象的getClass()的 isAnnotationPresent() 方法判斷它是否應(yīng)用了某個(gè)注解
User user = new User(); //開(kāi)文那個(gè)類(lèi)
System.out.println(user.getClass().isAnnotationPresent(Entity.class));//運(yùn)行結(jié)果: true
- public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
然后通過(guò) getAnnotation() 方法來(lái)獲取 Annotation 對(duì)象滤馍。
User user = new User();
System.out.println(user.getClass().getAnnotation(Entity.class).tableName());//運(yùn)行結(jié)果為user
public Annotation[] getAnnotations() {}
或者是 getAnnotations() 方法獲取所有的Annotation對(duì)象,包括繼承的public Annotation[] getDeclaredAnnotations()
獲取所有注解對(duì)象,不包括繼承的