反射是指程序能夠訪問,檢測,修改它自己狀態或行爲的一種能力。java
java的反射機制是指在程序運行狀態中,給定任意一個類,均可以獲取到這個類的屬性和方法;給定任意一個對象均可以調用這個對象的屬性和方法,這種動態的獲取類的信息和調用對象的方法的功能稱之爲java的反射機制。 一言以蔽之:反射機制可讓你在程序運行時,拿到任意一個類的屬性和方法並調用它。spring
想要理解反射首先須要知道Class這個類,它的全稱是java.lang.Class類。java是面向對象的語言,講究萬物皆對象,即便強大到一個類,它依然是另外一個類(Class類)的對象,換句話說,普通類是Class類的對象,即Class是全部類的類(There is a class named Class)。 對於普通的對象,咱們通常會這樣建立:數據庫
Code code1 = new Code();
複製代碼
上面說了,全部的類都是Class的對象,那麼如何表示呢,可不能夠經過以下方式呢:數組
Class c = new Class();
複製代碼
可是咱們查看Class的源碼時,是這樣寫的:bash
private Class(ClassLoader loader) {
classLoader = loader;
}
複製代碼
能夠看到構造器是私有的,只有JVM才能夠調用這個構造函數建立Class的對象,所以不能夠像普通類同樣new一個Class對象,雖然咱們不能new一個Class對象,可是卻能夠經過已有的類獲得一個Class對象,共有三種方式,以下:微信
Class c1 = Test.class; 這說明任何一個類都有一個隱含的靜態成員變量class,這種方式是經過獲取類的靜態成員變量class獲得的
Class c2 = test.getClass(); test是Test類的一個對象,這種方式是經過一個類的對象的getClass()方法得到的
Class c3 = Class.forName("com.catchu.me.reflect.Test"); 這種方法是Class類調用forName方法,經過一個類的全量限定名得到
複製代碼
這裏,c一、c二、c3都是Class的對象,他們是徹底同樣的,並且有個學名,叫作Test的類類型(class type)。 這裏就讓人奇怪了,前面不是說Test是Class的對象嗎,而c一、c二、c3也是Class的對象,那麼Test和c一、c二、c3不就同樣了嗎?爲何還叫Test什麼類類型?這裏不要糾結於它們是否相同,只要理解類類型是幹什麼的就行了,顧名思義,類類型就是類的類型,也就是描述一個類是什麼,都有哪些東西,因此咱們能夠經過類類型知道一個類的屬性和方法,而且能夠調用一個類的屬性和方法,這就是反射的基礎。 示例代碼:app
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<Test> class1 = Test.class;
System.out.println("類名1:"+class1.getName());
Test Test = new Test();
Class<? extends Test> class2 = Test.getClass();
System.out.println("類名2:"+class2.getName());
Class<?> class3 = Class.forName("com.catchu.me.reflect.Test");
System.out.println("類名3:"+class3.getName());
if(class1==class2){
System.out.println("class1==class2");
}
if(class1==class3){
System.out.println("class1==class3");
}
}
}
複製代碼
輸出結果:框架
類名1:com.catchu.me.reflect.Test
類名2:com.catchu.me.reflect.Test
類名3:com.catchu.me.reflect.Test
class1==class2
class1==class3
複製代碼
java的反射操做主要是用到了java.lang.Class類和java.lang.reflect反射包下的類,上面說到咱們已經能夠拿到一個類的Class信息,根據這個Class咱們就可使用某些方法來操做(獲取)類的如下信息:ide
萬物皆對象,類的構造函數是java.lang.reflect.Constructor類的對象,經過Class的下列方法能夠獲取構造函數對象:函數
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) // 得到該類全部的構造器,不包括其父類的構造器
public Constructor<T> getConstructor(Class<?>... parameterTypes) // 得到該類全部public構造器,包括父類
//具體
Constructor<?>[] allConstructors = class1.getDeclaredConstructors();//獲取class對象的全部聲明構造函數
Constructor<?>[] publicConstructors = class1.getConstructors();//獲取class對象public構造函數
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//獲取指定聲明構造函數(局部變量是一個字符串類型的)
Constructor publicConstructor = class1.getConstructor(String.class);//獲取指定聲明的public構造函數
複製代碼
測試代碼以下:
public class TestConstructor {
public static void main(String[] args) throws Exception{
Class<?> personClass = Class.forName("com.catchu.me.reflect.Person");
//獲取全部的構造函數,包括私有的,不包括父類的
Constructor<?>[] allConstructors = personClass.getDeclaredConstructors();
//獲取全部公有的構造函數,包括父類的
Constructor<?>[] publicConstructors = personClass.getConstructors();
System.out.println("遍歷以後的構造函數:");
for(Constructor c1 : allConstructors){
System.out.println(c1);
}
Constructor<?> c2 = personClass.getDeclaredConstructor(String.class);
c2.setAccessible(true); //設置是否可訪問,由於該構造器是private的,因此要手動設置容許訪問,若是構造器是public的就不用設置
Object person = c2.newInstance("劉俊重"); //使用反射建立Person類的對象,並傳入參數
System.out.println(person.toString());
}
}
複製代碼
Person類以下,爲測出效果包含一個私有構造函數:
public class Person {
private int age;
private String name;
public Person() {
}
private Person(String name){
this.name = name;
}
public Person(int age,String name){
this.age = age;
this.name = name;
}
//省略set/get方法
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' + '}'; } } 複製代碼
測試結果以下:
遍歷以後的構造函數:
public com.catchu.me.reflect.Person(int,java.lang.String)
private com.catchu.me.reflect.Person(java.lang.String)
public com.catchu.me.reflect.Person()
Person{age=0, name='劉俊重'}
複製代碼
由上面能夠看到咱們在得到某個類的Class類類型以後,能夠經過反射包中的方法獲取到這個類的構造函數,進而能夠建立該類的對象。
萬物皆對象,類的成員變量是java.lang.reflect.Field類的對象,經過Class類的如下方法能夠獲取某個類的成員變量,值得一提的是變量是包含兩部分的,變量類型和變量名:
public Field getDeclaredField(String name) // 得到該類自身聲明的全部變量,不包括其父類的變量
public Field getField(String name) // 得到該類自全部的public成員變量,包括其父類變量
//具體實現
Field[] allFields = class1.getDeclaredFields();//獲取class對象的全部屬性
Field[] publicFields = class1.getFields();//獲取class對象的public屬性
Field ageField = class1.getDeclaredField("age");//獲取class指定屬性
Field desField = class1.getField("des");//獲取class指定的public屬性
複製代碼
示例代碼以下:
public class TestField {
public static void main(String[] args) throws Exception{
Class<Person> personClass = Person.class;
//獲取全部的成員變量,包含私有的
Field[] allFields = personClass.getDeclaredFields();
//獲取全部公有的成員變量,包含父類的
Field[] publicFields = personClass.getFields();
System.out.println("全部的成員變量:");
for(Field f : allFields){
System.out.println(f);
}
//獲取某個變量的值
//建立對象的實例
Constructor<Person> c = personClass.getDeclaredConstructor(String.class);
c.setAccessible(true); //由於該構造函數時私有的,須要在這裏設置成可訪問的
Person person = c.newInstance("劉俊重");
//獲取變量name對象
Field field = personClass.getDeclaredField("name");
field.setAccessible(true); //由於變量name是私有的,須要在這裏設置成可訪問的
//注意對比下面這兩行,官方對field.get(Object obj)方法的解釋是返回對象obj字段field的值
Object value = field.get(person);
//String name = person.getName();
System.out.println("獲取的變量的值是:"+value);
}
}
複製代碼
輸出結果以下:
全部的成員變量:
private int com.catchu.me.reflect.Person.age
private java.lang.String com.catchu.me.reflect.Person.name
獲取的變量的值是:劉俊重
複製代碼
這裏要注意field.get(person)方法,咱們根據對象獲取屬性的常規方法是經過:String name = person.getName(),反射中能夠經過:字段.get(對象),這也是獲取對象的某個字段,有點相似於invoke方法。
萬物皆對象,類的成員方法是java.lang.reflect.Method的對象,經過java.lang.Class類的如下方法能夠獲取到類的成員方法,經過方法類Method提供的一些方法,又能夠調用獲取到的成員方法。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 獲得該類全部的方法,不包括父類的
public Method getMethod(String name, Class<?>... parameterTypes) // 獲得該類全部的public方法,包括父類的
//具體使用
Method[] methods = class1.getDeclaredMethods();//獲取class對象的全部聲明方法
Method[] allMethods = class1.getMethods();//獲取class對象的全部public方法 包括父類的方法
Method method = class1.getMethod("info", String.class);//返回此class1對應的public修飾的方法名是info的,包含一個String類型變量的方法
Method declaredMethod = class1.getDeclaredMethod("info", String.class);//返回此Class對象對應類的、帶指定形參列表的方法
複製代碼
測試代碼以下:
public class TestMethod {
public static void main(String[] args) throws Exception {
Person person = new Person();
Class<? extends Person> personClass = person.getClass();
Method[] allMethods = personClass.getDeclaredMethods();
Method[] publicMethods = personClass.getMethods();
System.out.println("遍歷全部的方法:");
for(Method m : allMethods){
System.out.println(m);
}
//下面是測試經過反射調用函數
//經過反射建立實例對象,默認調無參構造函數
Person person2 = personClass.newInstance();
//獲取要調用的方法,要調用study方法,包含int和String參數,注意int和Integer在這有區別
Method method = personClass.getMethod("study", int.class, String.class);
Object o = method.invoke(person2, 18, "劉俊重");
}
}
複製代碼
測試結果:
遍歷全部的方法:
public java.lang.String com.catchu.me.reflect.Person.toString()
public java.lang.String com.catchu.me.reflect.Person.getName()
public void com.catchu.me.reflect.Person.setName(java.lang.String)
public void com.catchu.me.reflect.Person.study(int,java.lang.String)
public int com.catchu.me.reflect.Person.getAge()
public void com.catchu.me.reflect.Person.setAge(int)
我叫劉俊重,我今年18,我在學習反射
複製代碼
注意:Object o = method.invoke(person2, 18, "劉俊重");就是調用person2對象的method方法,格式是:方法名.invoke(對象,參數),相似於獲取成員變量值時的get方法。 由上面能夠看出反射的強大:經過反射咱們能夠獲取到類類型,經過Class類型咱們能夠獲取到構造函數,進而實例化new出一個對象;經過反射咱們能夠獲取到成員變量和成員方法,經過實例出的對象又能夠獲取到這些成員變量的值或調用成員方法。這才只是反射的一部分,經過反射咱們還能夠判斷類,變量,方法,是否包含某些特定註解,還能夠經過反射來動態代理去調用其它方法,跟註解和動態代理掛起勾會有無限的想象空間,好比spring框架,底層就是經過這些原理。下面在說幾個反射經常使用的API,最後會介紹反射跟註解和動態代理的結合使用。
Annotation[] annotations = (Annotation[]) class1.getAnnotations();//獲取class對象的全部註解
Annotation annotation = (Annotation) class1.getAnnotation(Deprecated.class);//獲取class對象指定註解
Type genericSuperclass = class1.getGenericSuperclass();//獲取class對象的直接超類的
Type Type[] interfaceTypes = class1.getGenericInterfaces();//獲取class對象的全部接口的type集合
複製代碼
boolean isPrimitive = class1.isPrimitive();//判斷是不是基礎類型
boolean isArray = class1.isArray();//判斷是不是集合類
boolean isAnnotation = class1.isAnnotation();//判斷是不是註解類
boolean isInterface = class1.isInterface();//判斷是不是接口類
boolean isEnum = class1.isEnum();//判斷是不是枚舉類
boolean isAnonymousClass = class1.isAnonymousClass();//判斷是不是匿名內部類
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);//判斷是否被某個註解類修飾
String className = class1.getName();//獲取class名字 包含包名路徑
Package aPackage = class1.getPackage();//獲取class的包信息
String simpleName = class1.getSimpleName();//獲取class類名
int modifiers = class1.getModifiers();//獲取class訪問權限
Class<?>[] declaredClasses = class1.getDeclaredClasses();//內部類
Class<?> declaringClass = class1.getDeclaringClass();//外部類
ClassLoader ClassLoader = class1.getClassLoader() 返回類加載器
getSuperclass():獲取某類全部的父類
getInterfaces():獲取某類全部實現的接口
複製代碼
代理的操做是經過java.lang.reflect.Proxy 類中實現的,經過Proxy的newProxyInstance()方法能夠建立一個代理對象,以下:
public static Object newProxyInstance(ClassLoader loader,類<?>[] interfaces,InvocationHandler h)
複製代碼
不要看到這裏面一大坨晦澀的屎代碼就懼怕,這裏面是有技巧的,其實都是模板,須要什麼,咱們傳什麼過去就能夠了。能夠看到須要三個參數,類加載器,接口和調用處理者。咱們在上面已經能拿到Class類了,使用class.getClassLoader就能夠獲取類加載器,使用class.getgetInterfaces()能夠獲取全部的接口,那如今要寫的不就是新建一個InvocationHandler對象了嗎?事實上,咱們動態代理的核心代碼也就是在這裏面寫的。我上面說的模板,其實就是下面這幾步:
public interface PersonInterface {
void doSomething();
void saySomething();
}
複製代碼
接口的實現類:
public class PersonImpl implements PersonInterface {
@Override
public void doSomething() {
System.out.println("人類在作事");
}
@Override
public void saySomething() {
System.out.println("人類在說話");
}
}
複製代碼
代理類:
/**
* @author 劉俊重
*/
public class PersonProxy {
public static void main(String[] args) {
final PersonImpl person = new PersonImpl();
PersonInterface proxyPerson = (PersonInterface) Proxy.newProxyInstance(PersonImpl.class.getClassLoader(),
PersonImpl.class.getInterfaces(), new InvocationHandler() {
//在下面的invoke方法裏面寫咱們的業務
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName()=="doSomething"){
person.doSomething();
System.out.println("經過常規方法調用了實現類");
}else{
method.invoke(person,args);
System.out.println("經過反射機制調用了實現類");
}
return null;
}
});
proxyPerson.doSomething();
proxyPerson.saySomething();
}
}
複製代碼
執行結果以下:
人類在作事
經過常規方法調用了實現類
人類在說話
經過反射機制調用了實現類
複製代碼
在咱們經過proxyPerson.doSomething()調用的時候,其實不是立馬進入實現類的doSomething方法,而是帶着方法名,參數進入到了咱們的代理方法invoke裏面,在這裏面我進行了一次判斷,若是等於"doSomething"就使用常規方法調用,不然使用反射的方法調用。這樣看似仍是平時的調用,可是每次執行都要走咱們的代理方法裏面,咱們能夠在這裏面作些「手腳」,加入咱們的業務處理。 能夠看下面另外一個示例,好比天貓一件衣服正常賣50,如今你是個人vip用戶,能夠給你打折扣10塊,其它業務都是相同的,只有這裏便宜了10,從新服務提供者就很麻煩,用代理能夠解決這個問題。 接口SaleService:
public interface SaleService {
//根據尺碼返回衣服的大小
int clothes(String size);
}
複製代碼
接口實現類SaleServiceImpl:
public class SaleServiceImpl implements SaleService {
@Override
public int clothes(String size) {
System.out.println("衣服大小"+size);
//模擬從數據庫取衣服價格
return 50;
}
}
複製代碼
普通無折扣的調用測試:
/**
* @author 劉俊重
* @Description 普通用戶
*/
public class OrdinaryCustom {
public static void main(String[] args) {
SaleService saleService = new SaleServiceImpl();
int money = saleService.clothes("XXl");
System.out.println("價格是:"+money);
}
}
複製代碼
輸出結果:
衣服大小XXl
價格是:50
複製代碼
代理類ProxySale:
/**
* @author 劉俊重
* @Description 代理類
*/
public class ProxySale {
//對接口方法進行代理
public static <T> T getProxy(final int discount, final Class<SaleServiceImpl> implementClasses, Class<SaleService> interfaceClasses){
return (T)Proxy.newProxyInstance(implementClasses.getClassLoader(),
implementClasses.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//調用原始對象的方法,獲取未打折以前的價格
int price = (int) method.invoke(implementClasses.newInstance(), args);
return price-discount;
}
});
}
}
複製代碼
vip用戶測試類VipCustom:
/**
* @author 劉俊重
* @Description Vip用戶,有打折優惠
*/
public class VipCustom {
public static void main(String[] args) {
//vip用戶,打10元折扣
int discount = 10;
SaleService saleService = ProxySale.getProxy(discount, SaleServiceImpl.class, SaleService.class);
int money = saleService.clothes("xxl");
System.out.println("價格是:"+money);
}
}
複製代碼
輸出結果是:
衣服大小xxl
價格是:40
複製代碼
能夠看到,在未修改服務提供者的狀況下,咱們在代理類裏面作了手腳,結果符合預期。
@Override
void myMethod() {
......
}
複製代碼
這其中@Override就是註解。這個註解的做用也就是告訴編譯器,myMethod()方法覆蓋了父類中的myMethod()方法。
@Override:表示當前的方法定義將覆蓋超類中的方法,若是出現錯誤,編譯器就會報錯。
@Deprecated:若是使用此註解,編譯器會出現警告信息。
@SuppressWarnings:忽略編譯器的警告信息。
複製代碼
@Target
@Retention
@Documented
@Inherited
複製代碼
java8加了兩個新註解,後續我會講到。
@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
做用:用於描述註解的使用範圍(即:被描述的註解能夠用在什麼地方) 取值(ElementType)有:
類型 | 用途 |
---|---|
CONSTRUCTOR | 用於描述構造器 |
FIELD | 用於描述域 |
LOCAL_VARIABLE | 用於描述局部變量 |
METHOD | 用於描述方法 |
PACKAGE | 用於描述包 |
PARAMETER | 用於描述參數 |
TYPE | 用於描述類、接口(包括註解類型) 或enum聲明 |
好比定義下面一個註解,它就只能用在方法上,由於已經限定了它是方法級別的註解,若是用在類或者其它上面,編譯階段就會報錯:
@Target({ElementType.METHOD})
public @interface MyMethodAnnotation {
}
複製代碼
測試類MyClass:
//@MyMethodAnnotation 報錯,方法級別註解不能注在類頭上
public class MyClass {
@MyMethodAnnotation
public void myTestMethod(){
//
}
}
複製代碼
@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出如今源代碼中,而被編譯器丟棄;而另外一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另外一些在class被裝載時將被讀取(請注意並不影響class的執行,由於Annotation與class在使用上是被分離的)。使用這個meta-Annotation能夠對 Annotation的「生命週期」限制。
做用:表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效) 取值(RetentionPoicy)有:
類型 | 用途 | 說明 |
---|---|---|
SOURCE | 在源文件中有效(即源文件保留) | 僅出如今源代碼中,而被編譯器丟棄 |
CLASS | 在class文件中有效(即class保留) | 被編譯在class文件中 |
RUNTIME | 在運行時有效(即運行時保留) | 編譯在class文件中 |
示例:
@Target({ElementType.TYPE}) //用在描述類、接口或enum
@Retention(RetentionPolicy.RUNTIME) //運行時有效
public @interface MyClassAnnotation {
String value(); //這個MyClassAnnotation註解有個value屬性,未來能夠設置/獲取值
}
複製代碼
@Documented用於描述其它類型的annotation應該被做爲被標註的程序成員的公共API,所以能夠被例如javadoc此類的工具文檔化。Documented是一個標記註解,沒有成員。
做用:將註解包含在javadoc中
java.lang.annotation.Documented
@Documented
public @interface MyCustomAnnotation { //Annotation body}
複製代碼
是一個標記註解,闡述了某個被標註的類型是被繼承的,使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類,@Inherited annotation類型是被標註過的class的子類所繼承。類並不從實現的接口繼承annotation,方法不從它所重載的方法繼承annotation,當@Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。若是咱們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。
做用:容許子類繼承父類中的註解 示例,這裏的MyParentClass 使用的註解標註了@Inherited,因此子類能夠繼承這個註解信息:
java.lang.annotation.Inherited
@Inherited
public @interface MyCustomAnnotation {
}
@MyCustomAnnotation
public class MyParentClass {
...
}
public class MyChildClass extends MyParentClass {
...
}
複製代碼
格式
public @interface 註解名{
定義體
}
複製代碼
示例:
@Target(ElementType.FIELD)
@Retention(value=RetentionPolicy.RUNTIME)
@Documented
public @interface MyFieldAnnotation {
int id() default 0;
String name() default "";
}
複製代碼
定義了一個用在字段上的,運行時有效的名爲MyFieldAnnotation的註解,它有兩個屬性,int類型的id(id後面記得帶括號)默認值是0,還有一個String類型的name,默認值是""。
在上面咱們已經知道了怎麼自定義一個註解了,可是光定義沒用啊,重要的是我要使用它,使用的方法也很簡單,最上面講反射的時候也提到過幾個這樣的方法了,好比:class1.isAnnotation(),其實他們通通是java.lang.reflect包下的AnnotatedElement接口裏面的方法,這個接口主要有如下幾個實現類:
測試代碼CustomClassAnnotation以下:
/**
* @author 劉俊重
* @Description 自定義類註解
*/
@Target(ElementType.TYPE) //做用在類,枚舉或接口上
@Retention(RetentionPolicy.RUNTIME) //運行時有效
@Documented //文檔可見
public @interface CustomClassAnnotation {
String value(); //獲取註解名稱
}
複製代碼
FruitName類以下:
/**
* @author 劉俊重
* @Description 字段註解(字符串類型的)
*/
@Target(ElementType.FIELD) //用在字段上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
String name() default "";
}
複製代碼
FruitColor類以下:
/**
* @author 劉俊重
* @Description 字段註解(枚舉類型的)
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
//顏色枚舉
enum Color{BLUE,RED,GREEN};
//顏色屬性
Color color() default Color.RED;
}
複製代碼
Fruit實體類以下:
/**
* @author 劉俊重
* @Description Fruit實體類
*/
@CustomClassAnnotation(value="fruit")
public class Fruit{
@FruitName(name="apple")
private String name;
@FruitColor(color= FruitColor.Color.RED)
private String color;
}
複製代碼
測試類TestAnnotation以下:
/**
* @author 劉俊重
* @Description 測試類
*/
public class TestAnnotation {
public static void main(String[] args) {
Class<Fruit> clazz = Fruit.class; //反射獲取Class對象
CustomClassAnnotation annotation = clazz.getAnnotation(CustomClassAnnotation.class); //拿到Fruit類的註解
if(null!=annotation && "fruit".equals(annotation.value())){
System.out.println("Fruit類的註解名是======"+annotation.value());
//獲取全部的屬性遍歷,拿到每個屬性的值
Field[] allFields = clazz.getDeclaredFields();
for(Field field : allFields){
if(field.isAnnotationPresent(FruitName.class)){
//判斷是否存在FruitName註解
FruitName fruitName = field.getAnnotation(FruitName.class);
System.out.println("水果名稱====="+fruitName.name());
}
if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor = field.getAnnotation(FruitColor.class);
System.out.println("水果顏色====="+fruitColor.color());
}
}
}else{
System.out.println("註解值不對,請檢查");
}
}
}
複製代碼
總結:經過註解能夠獲取到類名,接口名,方法名,屬性名,再搭配反射能夠動態的生成對象,再搭配動態代理,去動態的去調用某些方法,這基本上也就是spring框架底層實現原理的一部分了。 注:本文一些內容引用自http://t.cn/RK8ci8w ,原做者反射和註解寫的確實不錯,我對部份內容進行了完善並重寫了部分示例;動態代理部分我加的,考慮着把反射,代理,註解放在一塊來講。
附一下我的微信公衆號,歡迎跟我交流。