https://github.com/zhaojiatao/javasehtml
Class對象是java程序用來建立類的全部常規對象用的;每一個類都有一個Class對象;java
當程序建立第一個對類的靜態成員(static修飾的成員以及構造方法)的引用時,就會加載這個類。類加載器首先檢查這個類的git
Class對象是否已經加載;若是還沒有加載,默認的類加載器就會查找.class文件。在加載字節碼後會執行安全驗證,以後會根程序員
據字節碼在內存中建立這個類的Class對象;github
這個例子會介紹第一種方法:使用Class類的forName()方法,獲取類的Class對象的引用;這個方法的反作用是,若是jvmweb
還未加載這個類的Class對象的話就加載這個類;在類加載的過程當中,會初始化static成員;spring
注意,傳遞給forName方法的名字,必須是全限定名;apache
此外,還可使用類字面常量的方法來生成對類Class對象的引用;設計模式
1 package thinkingInJava.chapter_14_classInfo; 2 3 4 /** 5 * @author zhaojiatao 6 * @date 2018/9/9 7 * 8 * 一、什麼是Class對象,Class對象是用來作什麼的? 9 * Class對象是java程序用來建立類的全部常規對象用的;每一個類都有一個Class對象; 10 * 二、Class對象是如何建立的? 11 * 當程序建立第一個對類的靜態成員(static修飾的成員以及構造方法)的引用時,就會加載這個類。類加載器首先檢查這個類的 12 * Class對象是否已經加載;若是還沒有加載,默認的類加載器就會查找.class文件。在加載字節碼後會執行安全驗證,以後會根 13 * 據字節碼在內存中建立這個類的Class對象; 14 * 三、除了jvm的類加載器會獲取某個類的Class對象以外,咱們本身如何獲取某個類的Class對象的引用? 15 * 這個例子會介紹第一種方法:使用Class類的forName()方法,獲取類的Class對象的引用;這個方法的反作用是,若是jvm 16 * 還又有加載這個類的Class對象的話就加載這個類;在類加載的過程當中,會初始化static成員; 17 * 注意,傳遞給forName方法的名字,必須是全限定名; 18 * 此外,還可使用類字面常量的方法來生成對類Class對象的引用; 19 * 20 * 21 */ 22 interface HasBatteries{} 23 24 interface Waterproof{} 25 26 interface Shoots{} 27 28 class Toy{ 29 Toy(){} 30 Toy(int i){} 31 } 32 33 class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{ 34 FancyToy(){ 35 super(1); 36 } 37 } 38 39 public class Test2 { 40 41 //經過Class對象,能夠獲得Class對象的多有信息 42 static void printInfo(Class cc){ 43 System.out.println("Class name:"+cc.getName()+"is interface?["+cc.isInterface()+"]"); 44 System.out.println("Simple name:"+cc.getSimpleName()); 45 System.out.println("Canonical name:"+cc.getCanonicalName()); 46 } 47 48 49 public static void main(String[] args) { 50 Class c=null; 51 52 try{ 53 //注意,必須使用全限定名 54 c=Class.forName("thinkingInJava.chapter_14_classInfo.FancyToy"); 55 }catch (ClassNotFoundException e){ 56 System.out.println("Can't find Test2"); 57 System.exit(1); 58 } 59 60 printInfo(c); 61 62 for(Class face:c.getInterfaces()){ 63 printInfo(face); 64 } 65 66 Class up=c.getSuperclass(); 67 Object obj=null; 68 try{ 69 //使用newInstance來建立的類,必須帶有默認構造器 70 obj=up.newInstance(); 71 }catch(InstantiationException e){ 72 System.out.println("Cannot instantiate"); 73 System.exit(1); 74 }catch (IllegalAccessException e){ 75 System.out.println("Cannot access"); 76 System.exit(1); 77 } 78 printInfo(obj.getClass()); 79 80 System.out.println(obj instanceof Toy); 81 82 } 83 84 85 }
除了使用class的forName方法獲取類的Class對象的引用外,還可使用類字面常量;數組
這種方式不只簡單,且更安全,由於會在類編譯期就進行安全檢查;
注意,使用.class的方式,獲取類的Class對象的引用,不會像forName()那樣初始化類的Class對象;
.class的方式僅僅是獲取了Class對象的引用,只有到了類真正被初始化結束後,Class對象才真正被初始化;即:
只有在對靜態方法或很是數靜態域進行首次引用時才執行初始化;
1 package thinkingInJava.chapter_14_classInfo; 2 3 import java.util.Random; 4 5 /** 6 * @author zhaojiatao 7 * @date 2018/9/10 8 * 9 * 除了使用class的forName方法獲取類的Class對象的引用外,還可使用類字面常量; 10 * 這種方式不只簡單,且更安全,由於會在類編譯期就進行安全檢查; 11 * 注意,使用.class的方式,獲取類的Class對象的引用,不會像forName()那樣初始化類的Class對象; 12 * .class的方式僅僅是獲取了Class對象的引用,只有到了類真正被初始化結束後,Class對象才真正被初始化;即: 13 * 只有在對靜態方法或很是數靜態域進行首次引用時才執行初始化; 14 * 15 */ 16 public class Test2_1 { 17 public static Random rand=new Random(47); 18 19 public static void main(String[] args) throws ClassNotFoundException { 20 Class initable=Initable.class; 21 System.out.println("這個時候僅僅是獲取到了Initable類的Class對象引用,Class對象還沒初始化"); 22 //對於static final值是編譯期常量,則該值無需對類初始化就能夠被讀取; 23 System.out.println(Initable.staticFinal); 24 //非編譯期常量,即便被static和final修飾,也必須先初始化類Class對象,才能讀取; 25 System.out.println(Initable.staticFinal2); 26 27 //若是一個static域不是final的,那麼在對它訪問時,老是要求在它被讀取以前,先進行連接(爲這個域分配存儲空間) 28 //以及初始化(初始化該存儲空間) 29 System.out.println(Initable2.staticNonFinal); 30 31 //使用forName方法,就會初始化類 32 Class initable3=Class.forName("thinkingInJava.chapter_14_classInfo.Initable3"); 33 System.out.println(Initable3.staticNonFinal); 34 35 36 37 } 38 39 } 40 41 42 class Initable{ 43 static final int staticFinal=47; 44 static final int staticFinal2=(int)(1+Math.random()*(10-1+1)); 45 static { 46 System.out.println("Initializing Initable"); 47 } 48 } 49 50 class Initable2{ 51 static int staticNonFinal=147; 52 static { 53 System.out.println("Initializing Initable2"); 54 } 55 } 56 57 class Initable3{ 58 static int staticNonFinal=74; 59 static{ 60 System.out.println("Initializing Initable3"); 61 } 62 }
1 package thinkingInJava.chapter_14_classInfo; 2 3 import org.junit.Test; 4 5 import java.util.ArrayList; 6 import java.util.List; 7 8 /** 9 * @author zhaojiatao 10 * @date 2018/9/11 11 * 12 * 13 * 學習範型在Class引用的使用過程的應用 14 * 15 * 16 */ 17 public class Test2_2 { 18 19 20 @Test 21 public void Test01() { 22 Class intClass=int.class; 23 Class<Integer> genericIntClass=int.class; 24 genericIntClass=Integer.class; 25 //若是將genericIntClass這個Class引用賦值給double.class的話,會因爲類型檢查失敗,是沒法編譯; 26 //genericIntClass=double.class; 27 //普通類的引用能夠賦值爲任何其餘的Class對象; 28 intClass = double.class; 29 } 30 31 32 //可使用通配符?代替上例中的<Integer>, 33 @Test 34 public void Test02() { 35 Class<?> intClass=int.class; 36 intClass = double.class; 37 } 38 39 //若是我像建立一個Class對象的引用,並指定這個Class對象的類型爲指定類型或其子類型,則須要使用? extend XXX 40 @Test 41 public void Test03() { 42 Class<? extends Number> bounded=int.class; 43 bounded = double.class; 44 bounded = Number.class; 45 } 46 47 //至此,能夠得出結論,使用範型語法的目的是爲了提供編譯期檢查; 48 49 @Test 50 public void Test04(){ 51 FilledList<CountedInteger> fl=new FilledList<CountedInteger>(CountedInteger.class); 52 System.out.println(fl.create(15)); 53 } 54 55 56 57 @Test 58 public void Test05() throws IllegalAccessException, InstantiationException { 59 Class<A> a=A.class; 60 A aa=a.newInstance(); 61 //注意,這裏若是不寫成這樣會報錯 62 Class<? super A> b=a.getSuperclass(); 63 64 //注意:b.newInstance返回的不是精確值,而是Object; 65 Object bb=b.newInstance(); 66 67 } 68 69 70 71 } 72 73 class CountedInteger{ 74 private static long counter; 75 private final long id=counter++; 76 public String toString(){ 77 return Long.toString(id); 78 } 79 } 80 81 82 //注意,因爲這個類中使用了type.newInstance()方法,因此,必須保證T傳進來的類有默認構造方法; 83 class FilledList<T>{ 84 private Class<T> type; 85 public FilledList(Class<T> type){ 86 this.type=type; 87 } 88 89 public List<T> create(int nElements){ 90 List<T> result=new ArrayList<T>(); 91 try{ 92 for(int i=0;i<nElements;i++){ 93 //注意,當在type上使用範型,newInstance()方法將產生肯定的類型; 94 result.add(type.newInstance()); 95 } 96 }catch (Exception e){ 97 e.printStackTrace(); 98 } 99 return result; 100 } 101 102 } 103 104 105 106 class A{ 107 108 } 109 110 class B extends A{ 111 112 }
在類型轉換以前先作檢查,若是貿然強制轉換,可能會拋出ClassCastException異常;
學習使用instance of 和isInstance()進行類型檢查;
主要區別就是instance of是編譯器進行類型檢查;
而 isInstance方法是運行期,動態進行類型檢查,可用於反射、泛型中;
1 package thinkingInJava.chapter_14_classInfo; 2 3 /** 4 * @author zhaojiatao 5 * @date 2018/9/11 6 * 7 * 在類型轉換以前先作檢查,若是貿然強制轉換,可能會拋出ClassCastException異常; 8 * 學習使用instance of 和isInstance()進行類型檢查; 9 * 主要區別就是instance of是編譯器進行類型檢查; 10 * 而 isInstance方法是運行期,動態進行類型檢查,可用於反射、泛型中; 11 * 12 */ 13 14 public class Test3 { 15 public static boolean DynamicEqual(Object fatherObj,Object sonObj){ 16 return fatherObj.getClass().isInstance(sonObj); // pass 17 // return sonObj.getClass().isInstance(fatherObj); 18 // return sonObj instanceof Father; // pass 19 // return sonObj instanceof (fatherObj.getClass()); //error 20 } 21 22 public static void main(String[] args){ 23 //instance of 編譯器類型檢查 24 Father father = new Father(); 25 Son son = new Son(); 26 27 System.out.println(son instanceof Son); // true 28 System.out.println(son instanceof Father); // true 29 System.out.println(son instanceof Object); // true 30 System.out.println(null instanceof Object); // false 31 System.out.println(); 32 33 //運行時動態類型檢查(括號裏的是子類) 34 System.out.println(Son.class.isInstance(son)); // true 35 //很明顯是錯誤的,但編譯是能夠經過的 36 System.out.println(Integer.class.isInstance(son));//false 37 System.out.println(Father.class.isInstance(son)); // true 38 System.out.println(Object.class.isInstance(son)); // true 39 System.out.println(Object.class.isInstance(null)); // false 40 System.out.println(); 41 42 43 //different using 44 System.out.println(DynamicEqual(father, son)); 45 } 46 47 48 } 49 50 class Father{} 51 52 class Son extends Father{}
工廠設計模式:將對象的建立工做交給類本身去完成;工廠方法能夠被多態地調用,從而爲你建立恰當類型的對象。
1 package thinkingInJava.chapter_14_classInfo; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.List; 6 import java.util.Random; 7 8 /** 9 * @author zhaojiatao 10 * @date 2018/9/12 11 * 工廠方法設計模式: 12 * 將對象的建立工做交給類本身去完成;工廠方法能夠被多態地調用,從而爲你建立恰當類型的對象。 13 */ 14 public class Test4 { 15 16 public static void main(String[] args) { 17 for(int i=0;i<10;i++){ 18 System.out.println(Part.createRandom()); 19 } 20 } 21 22 } 23 24 interface Factory<T>{ 25 T create(); 26 } 27 28 29 class Part{ 30 public String toString(){ 31 return getClass().getSimpleName(); 32 } 33 34 static List<Factory<? extends Part>> partFactories=new ArrayList<>(); 35 36 static { 37 /*partFactories.add(new FuelFilter.Factory()); 38 partFactories.add(new AirFilter.Factory()); 39 partFactories.add(new CabinAirFilter.Factory()); 40 partFactories.add(new OilFilter.Factory()); 41 42 partFactories.add(new FanBelt.Factory()); 43 partFactories.add(new GeneratorBelt.Factory()); 44 partFactories.add(new PowerSteeringBelt.Factory());*/ 45 Collections.addAll(partFactories,new FuelFilter.Factory(),new AirFilter.Factory(),new CabinAirFilter.Factory(), 46 new OilFilter.Factory(),new FanBelt.Factory(),new GeneratorBelt.Factory(),new PowerSteeringBelt.Factory() 47 ); 48 49 } 50 51 private static Random rand=new Random(47); 52 public static Part createRandom(){ 53 int n =rand.nextInt(partFactories.size()); 54 return partFactories.get(n).create(); 55 } 56 57 58 } 59 60 61 class Filter extends Part{} 62 63 class FuelFilter extends Filter{ 64 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<FuelFilter>{ 65 @Override 66 public FuelFilter create() { 67 return new FuelFilter(); 68 } 69 } 70 } 71 72 class AirFilter extends Filter{ 73 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<AirFilter>{ 74 @Override 75 public AirFilter create() { 76 return new AirFilter(); 77 } 78 } 79 } 80 81 class CabinAirFilter extends Filter{ 82 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<CabinAirFilter>{ 83 @Override 84 public CabinAirFilter create() { 85 return new CabinAirFilter(); 86 } 87 } 88 } 89 90 class OilFilter extends Filter{ 91 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<OilFilter>{ 92 @Override 93 public OilFilter create() { 94 return new OilFilter(); 95 } 96 } 97 } 98 99 100 class Belt extends Part{ 101 102 } 103 104 class FanBelt extends Belt{ 105 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<FanBelt>{ 106 @Override 107 public FanBelt create() { 108 return new FanBelt(); 109 } 110 } 111 } 112 113 class GeneratorBelt extends Belt{ 114 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<GeneratorBelt>{ 115 @Override 116 public GeneratorBelt create() { 117 return new GeneratorBelt(); 118 } 119 } 120 } 121 122 class PowerSteeringBelt extends Belt{ 123 public static class Factory implements thinkingInJava.chapter_14_classInfo.Factory<PowerSteeringBelt>{ 124 @Override 125 public PowerSteeringBelt create() { 126 return new PowerSteeringBelt(); 127 } 128 } 129 }
這一章節,其實主要就是講解instanceof、isInstance()、class對象== 三者的不一樣;
instanceof和isInstance()是一組,結果是相同的,區別在前文已經說過,前者須要在編譯器進行類型檢查,後者只在運行時進行類型檢查;
而比較class對象的==和equals一組,結果也是相同的,應爲equals是比較兩個class對象的內存地址是否一致;
但綜合起來看,這兩組的結果是不同的。instance和isInstance()考慮了繼承的狀況,然後一組沒有;
1 package thinkingInJava.chapter_14_classInfo; 2 3 /** 4 * @author zhaojiatao 5 * @date 2018/9/12 6 */ 7 public class Test5 { 8 public static void main(String[] args) { 9 FamilyVsExactType.test(new Base()); 10 FamilyVsExactType.test(new Derived()); 11 } 12 } 13 14 15 class Base{} 16 class Derived extends Base{} 17 18 class FamilyVsExactType { 19 static void test(Object x){ 20 System.out.println("Testing x of type "+x.getClass()); 21 System.out.println("x instanceof Base "+(x instanceof Base)); 22 System.out.println("x instanceof Derived "+Derived.class.isInstance(x)); 23 System.out.println("Base.isInstance(x) "+Base.class.isInstance(x)); 24 System.out.println("Derived.isInstance(x) "+Derived.class.isInstance(x)); 25 System.out.println("x.getClass()==Base.class "+(x.getClass()==Base.class)); 26 System.out.println("x.getClass()==Derived.class "+(x.getClass()==Derived.class)); 27 System.out.println("x.getClass().equals(Base.class) "+x.getClass().equals(Base.class)); 28 System.out.println("x.getClass().equals(Derived.class) "+x.getClass().equals(Derived.class)); 29 } 30 }
1、反射的適用場景是什麼?
1).Java的反射機制在作基礎框架的時候很是有用,有一句話這麼說來着:反射機制是不少Java框架的基石。而通常應用層面不多用,不過這種東西,如今不少開源框架基本都已經給你封裝好了,本身基本用不着寫。典型的除了Hibernate以外,還有Spring也用到不少反射機制。經典的就是在xml文件或者properties裏面寫好了配置,而後在Java類裏面解析xml或properties裏面的內容,獲得一個字符串,而後用反射機制,根據這個字符串得到某個類的Class實例,這樣就能夠動態配置一些東西,不用每一次都要在代碼裏面去new或者作其餘的事情,之後要改的話直接改配置文件,代碼維護起來就很方便了,同時有時候要適應某些需求,Java類裏面不必定能直接調用另外的方法,這時候也能夠經過反射機制來實現。
總的來講,本身寫的不多,具體何時要用那要看需求,反射機制無非就是根據一個String來獲得你要的實體對象,而後調用它原來的東西。可是若是是要本身寫框架的話,那就會用得比較多了。
2)當你作一個軟件能夠安裝插件的功能,你連插件的類型名稱都不知道,你怎麼實例化這個對象呢?由於程序是支持插件的(第三方的),在開發的時候並不知道 。因此沒法在代碼中 New出來 ,但反射能夠,經過反射,動態加載程序集,而後讀出類,檢查標記以後再實例化對象,就能夠得到正確的類實例。
3)在編碼階段不知道那個類名,要在運行期從配置文件讀取類名, 這時候就沒有辦法硬編碼new ClassName(),而必須用到反射才能建立這個對象.反射的目的就是爲了擴展未知的應用。好比你寫了一個程序,這個程序定義了一些接口,只要實現了這些接口的dll均可以做爲插件來插入到這個程序中。那麼怎麼實現呢?就能夠經過反射來實現。就是把dll加載進內存,而後經過反射的方式來調用dll中的方法。不少工廠模式就是使用的反射。
2、程序員在本身的業務開發中應該儘可能的遠離反射
反射:在流行的庫如Spring和Hibernate中,反射天然有其用武之地。不過內省業務代碼在不少時候都不是一件好事,緣由有不少,通常狀況下我老是建議你們不要使用反射。
首先是代碼可讀性與工具支持。打開熟悉的IDE,尋找你的Java代碼的內部依賴,很容易吧。如今,使用反射來替換掉你的代碼而後再試一下,結果如何呢?若是經過反射來修改已經封裝好的對象狀態,那麼結果將會變得更加不可控。請看看以下示例代碼:
若是這樣作就沒法獲得編譯期的安全保證。就像上面這個示例同樣,你會發現若是getDeclaredField()方法調用的參數輸錯了,那麼只有在運行期才能發現。要知道的是,尋找運行期Bug的難度要遠遠超過編譯期的Bug。
最後還要談談代價問題。JIT對反射的優化程度是不一樣的,有些優化時間會更長一些,而有些甚至是沒法應用優化。所以,有時反射的性能損失能夠達到幾個數量級的差異。不過在典型的業務應用中,你可能不會注意到這個代價。
總結一下,我以爲在業務代碼中惟一合理(直接)使用反射的場景是經過AOP。除此以外,你最好遠離反射這一特性。
3、性能分析
反射機制是一種程序自我分析的能力。用於獲取一個類的類變量,構造函數,方法,修飾符。
優勢:運行期類型的判斷,動態類加載,動態代理使用反射。
缺點:性能是一個問題,反射至關於一系列解釋操做,通知jvm要作的事情,性能比直接的java代碼要慢不少。
1 package thinkingInJava.chapter_14_classInfo; 2 3 import org.junit.Test; 4 5 import java.io.InputStream; 6 import java.lang.reflect.Constructor; 7 import java.lang.reflect.Field; 8 import java.lang.reflect.InvocationTargetException; 9 import java.lang.reflect.Method; 10 import java.util.ArrayList; 11 import java.util.Properties; 12 13 /** 14 * @author zhaojiatao 15 * @date 2018/9/13 16 * 17 * 反射的應用場景:https://blog.csdn.net/zolalad/article/details/29370565 18 * 反射的一些經常使用操做:參考:https://blog.csdn.net/sinat_38259539/article/details/71799078 19 * 20 */ 21 class Student { 22 23 //---------------構造方法------------------- 24 //(默認的構造方法) 25 Student(String str){ 26 System.out.println("(默認)的構造方法 s = " + str); 27 } 28 29 //無參構造方法 30 public Student(){ 31 System.out.println("調用了公有、無參構造方法執行了。。。"); 32 } 33 34 //有一個參數的構造方法 35 public Student(char name){ 36 System.out.println("姓名:" + name); 37 } 38 39 //有多個參數的構造方法 40 public Student(String name ,int age){ 41 System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,之後解決。 42 } 43 44 //受保護的構造方法 45 protected Student(boolean n){ 46 System.out.println("受保護的構造方法 n = " + n); 47 } 48 49 //私有構造方法 50 private Student(int age){ 51 System.out.println("私有的構造方法 年齡:"+ age); 52 } 53 54 55 //**********字段*************// 56 public String name; 57 protected int age; 58 char sex; 59 private String phoneNum; 60 61 62 63 64 //**************成員方法***************// 65 public void show1(String s){ 66 System.out.println("調用了:公有的,String參數的show1(): s = " + s); 67 } 68 protected void show2(){ 69 System.out.println("調用了:受保護的,無參的show2()"); 70 } 71 void show3(){ 72 System.out.println("調用了:默認的,無參的show3()"); 73 } 74 private String show4(int age){ 75 System.out.println("調用了,私有的,而且有返回值的,int參數的show4(): age = " + age); 76 return "abcd"; 77 } 78 79 80 81 @Override 82 public String toString() { 83 return "Student [name=" + name + ", age=" + age + ", sex=" + sex 84 + ", phoneNum=" + phoneNum + "]"; 85 } 86 87 88 public static void main(String[] args) { 89 System.out.println("main方法執行了。。。"); 90 } 91 92 public void show(){ 93 System.out.println("is show()"); 94 } 95 96 97 98 99 } 100 101 102 103 104 public class Test6 { 105 /* 106 * 經過Class對象能夠獲取某個類中的:構造方法、成員變量、成員方法;並訪問成員; 107 * 108 * 1.獲取構造方法: 109 * 1).批量的方法: 110 * public Constructor[] getConstructors():全部"公有的"構造方法 111 public Constructor[] getDeclaredConstructors():獲取全部的構造方法(包括私有、受保護、默認、公有) 112 113 * 2).獲取單個的方法,並調用: 114 * public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法: 115 * public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"能夠是私有的,或受保護、默認、公有; 116 * 117 * 調用構造方法: 118 * Constructor-->newInstance(Object... initargs) 119 * 120 * 2.設置字段的值: 121 * Field --> public void set(Object obj,Object value): 122 * 參數說明: 123 * 1.obj:要設置的字段所在的對象; 124 * 2.value:要爲字段設置的值; 125 * 126 * 127 */ 128 129 130 131 //經過反射獲取構造方法並使用 132 @Test 133 public void test01() { 134 135 //1.加載Class對象 136 Class clazz = null; 137 try { 138 clazz = Class.forName("thinkingInJava.chapter_14_classInfo.Student"); 139 } catch (ClassNotFoundException e) { 140 e.printStackTrace(); 141 } 142 143 //2.獲取全部公有構造方法 144 System.out.println("**********************全部公有構造方法*********************************"); 145 //Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object. 146 Constructor[] conArray = clazz.getConstructors(); 147 for(Constructor c : conArray){ 148 System.out.println(c); 149 } 150 151 System.out.println("************全部的構造方法(包括:私有、受保護、默認、公有)***************"); 152 //Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. 153 conArray = clazz.getDeclaredConstructors(); 154 for(Constructor c : conArray){ 155 System.out.println(c); 156 } 157 158 System.out.println("*****************獲取公有、無參的構造方法*******************************"); 159 Constructor con = null; 160 try { 161 con = clazz.getConstructor(null); 162 } catch (NoSuchMethodException e) { 163 e.printStackTrace(); 164 } 165 //1>、由於是無參的構造方法因此類型是一個null,不寫也能夠:這裏須要的是一個參數的類型,切記是類型 166 //2>、返回的是描述這個無參構造函數的類對象。 167 168 System.out.println("con = " + con); 169 //調用構造方法 170 Object obj = null; 171 try { 172 obj = con.newInstance(); 173 } catch (InstantiationException e) { 174 e.printStackTrace(); 175 } catch (IllegalAccessException e) { 176 e.printStackTrace(); 177 } catch (InvocationTargetException e) { 178 e.printStackTrace(); 179 } 180 System.out.println("obj = " + obj); 181 Student stu = (Student)obj; 182 System.out.println("使用無參構造方法建立的Student對象的實例:stu="+stu.toString()); 183 184 System.out.println("******************獲取私有構造方法,並調用*******************************"); 185 try { 186 con = clazz.getDeclaredConstructor(char.class); 187 } catch (NoSuchMethodException e) { 188 e.printStackTrace(); 189 } 190 System.out.println(con); 191 //調用構造方法 192 con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符) 193 try { 194 obj = con.newInstance('男'); 195 } catch (InstantiationException e) { 196 e.printStackTrace(); 197 } catch (IllegalAccessException e) { 198 e.printStackTrace(); 199 } catch (InvocationTargetException e) { 200 e.printStackTrace(); 201 } 202 203 System.out.println("obj = " + obj); 204 stu = (Student)obj; 205 System.out.println("使用私有構造方法建立的Student對象的實例:stu="+stu.toString()); 206 207 } 208 209 210 211 212 //獲取成員變量並調用 213 @Test 214 public void test02() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, 215 InvocationTargetException, InstantiationException { 216 //1.獲取Class對象 217 Class stuClass = Class.forName("thinkingInJava.chapter_14_classInfo.Student"); 218 //2.獲取字段 219 System.out.println("************獲取全部公有的字段********************"); 220 Field[] fieldArray = stuClass.getFields(); 221 for(Field f : fieldArray){ 222 System.out.println(f); 223 } 224 System.out.println("************獲取全部的字段(包括私有、受保護、默認的)********************"); 225 fieldArray = stuClass.getDeclaredFields(); 226 for(Field f : fieldArray){ 227 System.out.println(f); 228 } 229 System.out.println("*************獲取公有字段xx並調用***********************************"); 230 Field f = stuClass.getField("name"); 231 System.out.println(f); 232 //獲取一個對象 233 Object obj = stuClass.getConstructor().newInstance();//產生Student對象--》Student stu = new Student(); 234 //爲字段設置值 235 f.set(obj, "劉德華");//爲Student對象中的name屬性賦值--》stu.name = "劉德華" 236 //驗證 237 Student stu = (Student)obj; 238 System.out.println("驗證姓名:" + stu.name); 239 240 241 System.out.println("**************獲取私有字段****並調用********************************"); 242 f = stuClass.getDeclaredField("phoneNum"); 243 System.out.println(f); 244 f.setAccessible(true);//暴力反射,解除私有限定 245 f.set(obj, "18888889999"); 246 System.out.println("驗證電話:" + stu); 247 248 } 249 250 251 252 //獲取成員方法並調用 253 @Test 254 public void test03() throws Exception { 255 256 //1.獲取Class對象 257 Class stuClass = Class.forName("thinkingInJava.chapter_14_classInfo.Student"); 258 //2.獲取全部公有方法 259 System.out.println("***************獲取全部的」公有「方法*******************"); 260 stuClass.getMethods(); 261 Method[] methodArray = stuClass.getMethods(); 262 for(Method m : methodArray){ 263 System.out.println(m); 264 } 265 System.out.println("***************獲取全部的方法,包括私有的*******************"); 266 methodArray = stuClass.getDeclaredMethods(); 267 for(Method m : methodArray){ 268 System.out.println(m); 269 } 270 System.out.println("***************獲取公有的show1()方法*******************"); 271 Method m = stuClass.getMethod("show1", String.class); 272 System.out.println(m); 273 //實例化一個Student對象 274 Object obj = stuClass.getConstructor().newInstance(); 275 m.invoke(obj, "劉德華"); 276 277 System.out.println("***************獲取私有的show4()方法******************"); 278 m = stuClass.getDeclaredMethod("show4", int.class); 279 System.out.println(m); 280 m.setAccessible(true);//解除私有限定 281 Object result = m.invoke(obj, 20);//須要兩個參數,一個是要調用的對象(獲取有反射),一個是實參 282 System.out.println("返回值:" + result); 283 284 285 286 287 } 288 289 290 //反射main方法 291 @Test 292 public void test04(){ 293 try { 294 //一、獲取Student對象的字節碼 295 Class clazz = Class.forName("thinkingInJava.chapter_14_classInfo.Student"); 296 297 //二、獲取main方法 298 Method methodMain = clazz.getMethod("main", String[].class);//第一個參數:方法名稱,第二個參數:方法形參的類型, 299 //三、調用main方法 300 // methodMain.invoke(null, new String[]{"a","b","c"}); 301 //第一個參數,對象類型,由於方法是static靜態的,因此爲null能夠,第二個參數是String數組,這裏要注意在jdk1.4時是數組,jdk1.5以後是可變參數 302 //這裏拆的時候將 new String[]{"a","b","c"} 拆成3個對象。。。因此須要將它強轉。 303 methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一 304 //methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二 305 306 } catch (Exception e) { 307 e.printStackTrace(); 308 } 309 310 } 311 312 313 314 //反射方法的其它使用之---經過反射運行配置文件內容 315 @Test 316 public void test05() throws Exception { 317 Properties pro = new Properties(); 318 {//此方式要求 配置文件在 src 文件夾 內 319 320 //類名.class.getClassLoader().getResourceAsStream("文件名") 321 InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("pro.properties"); 322 pro.load(inStream); 323 inStream.close(); 324 } 325 326 //經過反射獲取Class對象 327 Class stuClass = Class.forName(pro.getProperty("className"));//"cn.fanshe.Student" 328 //2獲取show()方法 329 Method m = stuClass.getMethod(pro.getProperty("methodName"));//show 330 //3.調用show()方法 331 m.invoke(stuClass.getConstructor().newInstance()); 332 333 } 334 335 336 337 //反射方法的其它使用之---經過反射越過泛型檢查 338 @Test 339 public void test06() throws Exception{ 340 ArrayList<String> strList = new ArrayList<String>(); 341 strList.add("aaa"); 342 strList.add("bbb"); 343 344 // strList.add(100); 345 //獲取ArrayList的Class對象,反向的調用add()方法,添加數據 346 Class listClass = strList.getClass(); //獲得 strList 對象的字節碼 對象 347 //獲取add()方法 348 Method m = listClass.getMethod("add", Object.class); 349 //調用add()方法 350 m.invoke(strList, 100); 351 352 //遍歷集合 353 for(Object obj : strList){ 354 System.out.println(obj); 355 } 356 357 } 358 359 360 361 362 363 }
內省(Introspector) 是Java 語言對 JavaBean 類屬性、事件的一種缺省處理方法。
JavaBean是一種特殊的類,主要用於傳遞數據信息,這種類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。若是在兩個模塊之間傳遞信息,能夠將信息封裝進JavaBean中,這種對象稱爲「值對象」(Value Object),或「VO」。方法比較少。這些信息儲存在類的私有變量中,經過set()、get()得到。
在框架設計的時候使用比較多,像mybatis中類與表的映射關係的類的屬性與表的列一一對應,框架在賦值和獲取值得時候會調用對應的setter和getter方法;
例如spring 中初始化bean的時候取藥用到反射的方式實例化bean,在set值的時候會根據變量名得到settter方法,把配置好的值set進去;
1 package thinkingInJava.chapter_14_classInfo; 2 3 import org.apache.commons.beanutils.BeanUtils; 4 import org.apache.commons.beanutils.PropertyUtils; 5 import org.junit.Test; 6 7 import java.beans.BeanInfo; 8 import java.beans.IntrospectionException; 9 import java.beans.Introspector; 10 import java.beans.PropertyDescriptor; 11 import java.lang.reflect.InvocationTargetException; 12 import java.lang.reflect.Method; 13 14 /** 15 * @author zhaojiatao 16 * @date 2018/9/13 17 * 18 * 內省: 19 * http://www.cnblogs.com/peida/archive/2013/06/03/3090842.html 20 * https://blog.csdn.net/u010445297/article/details/60967146 21 * 22 */ 23 public class Test6_Introspector { 24 25 public static void main(String[] args) { 26 UserInfo userInfo=new UserInfo(); 27 userInfo.setUserName("peida"); 28 try { 29 BeanInfoUtil.getProperty(userInfo, "userName"); 30 31 BeanInfoUtil.setProperty(userInfo, "userName"); 32 33 BeanInfoUtil.getProperty(userInfo, "userName"); 34 35 BeanInfoUtil.setPropertyByIntrospector(userInfo, "userName"); 36 37 BeanInfoUtil.getPropertyByIntrospector(userInfo, "userName"); 38 39 BeanInfoUtil.setProperty(userInfo, "age"); 40 //說明:BeanInfoUtil.setProperty(userInfo, "age");報錯是應爲age屬性是int數據類型, 41 //而setProperty方法裏面默認給age屬性賦的值是String類型。因此會爆出argument type mismatch參數類型不匹配的錯誤信息。 42 43 } catch (Exception e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } 47 48 } 49 50 51 52 @Test 53 public void testBeanUtils(){ 54 UserInfo userInfo=new UserInfo(); 55 try { 56 BeanUtils.setProperty(userInfo, "userName", "peida"); 57 58 System.out.println("set userName:"+userInfo.getUserName()); 59 60 System.out.println("get userName:"+BeanUtils.getProperty(userInfo, "userName")); 61 62 BeanUtils.setProperty(userInfo, "age", 18); 63 System.out.println("set age:"+userInfo.getAge()); 64 65 System.out.println("get age:"+BeanUtils.getProperty(userInfo, "age")); 66 67 System.out.println("get userName type:"+BeanUtils.getProperty(userInfo, "userName").getClass().getName()); 68 System.out.println("get age type:"+BeanUtils.getProperty(userInfo, "age").getClass().getName()); 69 70 PropertyUtils.setProperty(userInfo, "age", 8); 71 System.out.println(PropertyUtils.getProperty(userInfo, "age")); 72 73 System.out.println(PropertyUtils.getProperty(userInfo, "age").getClass().getName()); 74 75 PropertyUtils.setProperty(userInfo, "age", "8"); 76 } 77 catch (IllegalAccessException e) { 78 e.printStackTrace(); 79 } 80 catch (InvocationTargetException e) { 81 e.printStackTrace(); 82 } 83 catch (NoSuchMethodException e) { 84 e.printStackTrace(); 85 } 86 } 87 88 89 90 } 91 92 93 class BeanInfoUtil { 94 95 public static void setProperty(UserInfo userInfo,String userName){ 96 PropertyDescriptor propDesc= null; 97 try { 98 propDesc = new PropertyDescriptor(userName,UserInfo.class); 99 } catch (IntrospectionException e) { 100 e.printStackTrace(); 101 } 102 Method methodSetUserName=propDesc.getWriteMethod(); 103 try { 104 methodSetUserName.invoke(userInfo, "wong"); 105 } catch (IllegalAccessException e) { 106 e.printStackTrace(); 107 } catch (InvocationTargetException e) { 108 e.printStackTrace(); 109 } 110 System.out.println("set userName:"+userInfo.getUserName()); 111 } 112 113 public static void getProperty(UserInfo userInfo,String userName){ 114 PropertyDescriptor proDescriptor = null; 115 try { 116 proDescriptor = new PropertyDescriptor(userName,UserInfo.class); 117 } catch (IntrospectionException e) { 118 e.printStackTrace(); 119 } 120 Method methodGetUserName=proDescriptor.getReadMethod(); 121 Object objUserName= null; 122 try { 123 objUserName = methodGetUserName.invoke(userInfo); 124 } catch (IllegalAccessException e) { 125 e.printStackTrace(); 126 } catch (InvocationTargetException e) { 127 e.printStackTrace(); 128 } 129 System.out.println("get userName:"+objUserName.toString()); 130 } 131 132 public static void setPropertyByIntrospector(UserInfo userInfo,String userName){ 133 BeanInfo beanInfo= null; 134 try { 135 beanInfo = Introspector.getBeanInfo(UserInfo.class); 136 } catch (IntrospectionException e) { 137 e.printStackTrace(); 138 } 139 PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors(); 140 if(proDescrtptors!=null&&proDescrtptors.length>0){ 141 for(PropertyDescriptor propDesc:proDescrtptors){ 142 if(propDesc.getName().equals(userName)){ 143 Method methodSetUserName=propDesc.getWriteMethod(); 144 try { 145 methodSetUserName.invoke(userInfo, "alan"); 146 } catch (IllegalAccessException e) { 147 e.printStackTrace(); 148 } catch (InvocationTargetException e) { 149 e.printStackTrace(); 150 } 151 System.out.println("set userName:"+userInfo.getUserName()); 152 break; 153 } 154 } 155 } 156 } 157 158 public static void getPropertyByIntrospector(UserInfo userInfo,String userName){ 159 BeanInfo beanInfo= null; 160 try { 161 beanInfo = Introspector.getBeanInfo(UserInfo.class); 162 } catch (IntrospectionException e) { 163 e.printStackTrace(); 164 } 165 PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors(); 166 if(proDescrtptors!=null&&proDescrtptors.length>0){ 167 for(PropertyDescriptor propDesc:proDescrtptors){ 168 if(propDesc.getName().equals(userName)){ 169 Method methodGetUserName=propDesc.getReadMethod(); 170 Object objUserName= null; 171 try { 172 objUserName = methodGetUserName.invoke(userInfo); 173 } catch (IllegalAccessException e) { 174 e.printStackTrace(); 175 } catch (InvocationTargetException e) { 176 e.printStackTrace(); 177 } 178 System.out.println("get userName:"+objUserName.toString()); 179 break; 180 } 181 } 182 } 183 } 184 } 185 186 187 188 class UserInfo { 189 190 private long userId; 191 private String userName; 192 private int age; 193 private String emailAddress; 194 195 public long getUserId() { 196 return userId; 197 } 198 public void setUserId(long userId) { 199 this.userId = userId; 200 } 201 public String getUserName() { 202 return userName; 203 } 204 public void setUserName(String userName) { 205 this.userName = userName; 206 } 207 public int getAge() { 208 return age; 209 } 210 public void setAge(int age) { 211 this.age = age; 212 } 213 public String getEmailAddress() { 214 return emailAddress; 215 } 216 public void setEmailAddress(String emailAddress) { 217 this.emailAddress = emailAddress; 218 } 219 220 }
jdk的動態代理依賴接口,有侷限性;底層是經過反射,執行method;