注解和反射
本筆記是在學(xué)習(xí)狂神說java的B站視頻記錄的。
什么是注解
Annotation是從JDK5.0開始引入的新技術(shù)。
作用
- 不是程序本身,可以對程序作出解釋
- 可以被其他程序(比如:編譯器等)讀取
格式
@注釋名,還可以加一些參數(shù)值
在哪里使用
可以附加在package、class、method、field上
可以通過反射機制編程實現(xiàn)這些元數(shù)據(jù)的訪問
內(nèi)置注解
@Override:重寫超類的方法
@Deprecated:廢棄
@SuppressWarnings("xxx"):用來抑制編譯時的警告信息,需傳value值
元注解
- 元注解的作用就是負責(zé)注解其他注解,Java定義了4個標準的meta-annotation類型,他們被用來提供對其他annotation類型作說明
- 這些類型和它們所支持的類在java.lang.annotation包中可以找到
- @Target:用于描述注解的使用范圍
- @Retention:表示需要在什么級別保存注釋信息,用于描述注解的生命周期
- @Document:說明該注解將包含在javadoc中
- @Inherited:說明子類可以繼承父類中的該注解
自定義注解
使用@interface自定義注解時,自動繼承了java.lang.Annotation接口
- 聲明格式:public @interface 注解名{ 定義內(nèi)容 }
- 其中的每一個方法實際上是聲明了一個配置參數(shù)
- 方法的名稱就是參數(shù)的名稱
- 返回值類型就是參數(shù)的類型(返回值只能是基本類型,Class,String,enum)
- 可以通過default來聲明參數(shù)的默認值
- 如果只有一個參數(shù)成員,一般參數(shù)名為value
- 注解元素必須要有值,我們定義注解元素時,經(jīng)常使用空字符串,0作為默認值
反射機制
靜態(tài)vs動態(tài)語言
動態(tài)語言
運行時可以改變其結(jié)構(gòu)的語言:Object-C,C#,JavaScript,PHP,Python
靜態(tài)語言
運行時結(jié)構(gòu)不可變:Java,C,C++
Java不是動態(tài)語言,但能通過反射機制獲得類似動態(tài)語言的特性,稱為“準動態(tài)語言”
Java Reflection
-
反射是Java被視為動態(tài)語言的關(guān)鍵,反射機制允許程序在執(zhí)行期借助于Reflection API 取得任何類的內(nèi)部信息,并能操作任意對象的內(nèi)部屬性及方法。
Class c = Class.forName("java.lang.String") 加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個對象看到類的結(jié)構(gòu),這個對象就像一面鏡子,透過鏡子看到類的結(jié)構(gòu),所以稱之為:反射

優(yōu)點:可以實現(xiàn)動態(tài)創(chuàng)建對象好編譯,體現(xiàn)出很大的靈活性
缺點:對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于直接執(zhí)行相同的操作。
反射相關(guān)的API
- java.lang.Class:代表一個類
- java.lang.reflect.Method:代表類的方法
- java.lang.reflect.Field:代表類的成員變量
- java.lang.reflect.Constructor:代表類的構(gòu)造器
Class類
在Object類中定義了public final Class getClass(),此方法被所有子類繼承

由樹可知,所有的對象都指向Class。
以上的方法返回值的類型是一個Class類,此類是反射的源頭,即:通過對象反射求出類的名稱。
對象照鏡子后可以得到的信息:某個類的屬性、方法和構(gòu)造器、某類到底實現(xiàn)了哪些接口。
Class類的常用方法

獲取Class類的實例
- 類的class屬性獲?。?code>Class c = Student.class;
- 調(diào)用該實例的getClass()方法獲?。?code>Class c = person.getClass();
- 調(diào)用Class類靜態(tài)方法forName()獲取:
Class c = Class.forName("xxx"); - 基本內(nèi)置類型的包裝類用類名.Type獲?。?code>Class c = Integer.TYPE;
- 還有利用ClassLoader
哪些類型可以有Class對象
- class:外部類,成員(成員內(nèi)部類,靜態(tài)內(nèi)部類),局部內(nèi)部類,匿名內(nèi)部類
- interface:接口
- []:數(shù)組
- enum:枚舉
- annotation:注解@interface
- primitive type:基本數(shù)據(jù)類型
- void
Java內(nèi)存分析

類加載過程

static在初始化之前就已經(jīng)存在,鏈接的時候準備的,可以直接調(diào)用
什么時候會發(fā)生類初始化
- 類的主動引用(一定會發(fā)生類的初始化)
- 當虛擬機啟動,先初始化main方法所在的類
- new一個類的對象
- 調(diào)用類的靜態(tài)成員(除了final常量)和靜態(tài)方法
- 使用java.lang.reflect包的方法對類進行反射調(diào)用
- 當初始化一個類,如果其父類沒有被初始化,則先會初始化它的父類
- 類的被動引用(不會發(fā)生類的初始化)
- 當訪問一個靜態(tài)域時,只有真正聲明這個域的類才會被初始化。如:當通過子類引用父類的靜態(tài)變量,不會導(dǎo)致子類初始化
- 通過數(shù)組定義類引用,不會觸發(fā)此類的初始化
- 引用常量不會觸發(fā)此類的初始化(常量在鏈接階段就存入調(diào)用類的常量池中了)
類加載器的作用
- 類加載的作用:將class文件字節(jié)碼內(nèi)容加載到內(nèi)存中,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu),然后在堆中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)中類數(shù)據(jù)的訪問入口。
- 類緩存:標準的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器中,它將維持加載(緩存)一段時間。不過JVM垃圾回收機制可以回收這些Class對象。

有了Class對象,能做什么?
- 創(chuàng)建類的對象:調(diào)用Clss對象的newInstance()方法
- 類必須有一個無參數(shù)的構(gòu)造器
- 類的構(gòu)造器的訪問權(quán)限需要足夠
- 沒有無參構(gòu)造器用有參構(gòu)造傳遞參數(shù)
調(diào)用指定的方法
- 通過Class類的getMethod方法
- 使用Object.invoke進行調(diào)用

setAccessible
若原方法聲明為private,則需用setAccessible(true)方法才可訪問
Method和Field、Constructor對象都有setAccessible
setAccessible作用是啟動和禁用訪問安全檢查的開關(guān)
提高反射效率
反射操作泛型
- ParameterizedType:表示一種參數(shù)化類型,比如
Collection<String> - GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
- TypeVariable:是各種類型變量的公共父接口
- WildcardType:代表一種通配符類型表達式
反射操作注解
getAnnotations
getAnnotation
了解什么是ORM?
Object relationship Mapping --> 對象關(guān)系映射
利用注解和反射完成類和表結(jié)構(gòu)的映射關(guān)系