第一講:透徹分析反射的基礎_Class類java
一,反射的基石——Class類的瞭解:web
二,獲得字節碼的三種方式:算法
三,八個基本數據類型都有對應的Class對象,而且與其包裝類所對應的Class對象不一樣。void 也有對應的Class對象。設計模式
四,代碼練習:數組
1 public class ReflectTest { 2 public static void main(String[] args) throws ClassNotFoundException { 3 4 //建立一個String對象 5 String str = "abc"; 6 7 //經過三個方式得到String的Class對象。 8 Class c1 = str.getClass(); 9 Class c2 = String.class; 10 Class c3 = Class.forName("java.lang.String"); 11 12 //判斷是不是同一份字節碼。 13 System.out.println(c1==c2); 14 System.out.println(c2==c3); 15 16 //是不是基本類型 17 System.out.println(c1.isPrimitive()); 18 19 //基本類型和包裝類型的字節碼文件是不一樣的 20 System.out.println(int.class==Integer.class); 21 22 //能夠經過包裝類型得到其包裝的基本類型的字節碼 23 System.out.println(int.class==Integer.TYPE); 24 25 //判斷數字是不是一個原始類型 26 System.out.println(int[].class.isPrimitive()); 27 28 //判斷一個字節碼是不是數組類型 29 System.out.println(int[].class.isArray()); 30 31 } 32 }
第二講:理解反射的概念eclipse
一,反射:把java類中的各類成分映射成響應的java類。ide
二,Class類中獲取信息的方法:工具
Constructor
對象,它反映此 Class
對象所表示的類的指定公共構造方法。Constructor
對象的數組,這些對象反映此 Class
Constructor
對象的一個數組,這些對象反映此 Class
對象表示的類聲明的全部構造方法。Field
對象,它反映此 Class
對象所表示的類或接口的指定公共成員字段。Method
對象的數組第三講:構造方法的反射應用性能
一,Constructor類的瞭解:學習
Constructor
提供關於類的單個構造方法的信息以及對它的訪問權限。Class
對象,該對象表示聲明由此 Constructor
對象表示的構造方法的類。Constructor
對象所表示構造方法的 Java 語言修飾符。Class
對象,這些對象表示此 Constructor
對象所表示構造方法的形參類型。若是底層構造方法不帶任何參數,則返回一個長度爲 0 的數組。Constructor
對象表示的構造方法來建立該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。二,明確程序的,編譯時和運行時:
三,建立一個對象的三種方式:
四,代碼練習:
1 import java.lang.reflect.*; 2 3 4 public class Reflect_Method { 5 public static void main(String[] args) throws Exception { 6 7 //獲取一個Class對象的指定構造方法 8 Constructor m = String.class.getConstructor(StringBuffer.class); 9 10 // 經過方法對象,建立類的對象 11 String s = (String) m.newInstance(new StringBuffer("abc")); 12 13 //經過Class對象建立類對象 14 String s2 = String.class.newInstance(); 15 16 s2="a"; 17 18 //直接實例化 19 String s3 = new String("abc"); 20 21 22 System.out.println(s.charAt(2)); 23 24 System.out.println(s2); 25 26 System.out.println(s3); 27 } 28 }
第四講,第五講:成員變量的反射,成員變量反射的綜合案例
一,Field 類的瞭解:
ield
提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段多是一個類(靜態)字段或實例字段。Field
表示的字段的值。若是該值是一個基本類型值,則自動將其包裝在一個對象中。boolean
字段的值。====此方法根據多種數據類型有多個重載方法。====Field
對象表示的字段的 Java 語言修飾符。應該使用 Modifier
類對這些修飾符進行解碼。Field
對象表示的字段的名稱。boolean
值。。====此方法根據多種數據類型有多個重載方法。=============Field對象表示的不是對象的成員,而是類的成員==========
二,代碼練習:
1 import java.lang.reflect.*; 2 3 4 //定義用來反射操做的類 5 class ReflectPoint { 6 private int x; 7 public int y; 8 9 public String str1 = "ball"; 10 public String str2 = "basketball"; 11 public String str3 = "itcase"; 12 13 public ReflectPoint(int x, int y) { 14 this.x = x; 15 this.y = y; 16 } 17 18 public String toString(){ 19 return str1+"::"+str2+"::"+str3; 20 } 21 }
1 import java.util.Arrays; 2 3 4 public class Reflect_Array { 5 public static void main(String[] args) { 6 7 //分別定義不一樣維數,不一樣類型的數組 8 int[] a1 = new int[]{1,2,3}; 9 int[] a2 = new int[5]; 10 int[][] a3 = new int[2][4]; 11 String[] a4 = new String[]{"a","b","c"}; 12 13 //具備相同維數相同類型的數組是共享一個字節碼對象的 14 System.out.println(a1.getClass() == a2.getClass()); 15 16 //下面這句話編譯期出錯 17 //System.out.println(a1.getClass() == a4.getClass()); 18 19 //獲取數組的字節碼名字即類名 20 System.out.println(a1.getClass().getName()); 21 System.out.println(a4.getClass().getName()); 22 23 //獲取數組的父類名字 24 System.out.println(a4.getClass().getSuperclass().getName()); 25 26 27 //數組是Object的子類,向上轉型 28 Object obj = a1; 29 Object obj2 = a3; 30 31 //Object[] objs = a1; 32 33 //引用類型數組,能夠向父類型數組轉型 34 Object[] objs2 = a4; 35 Object[] objs3 = a3; 36 37 System.out.println(obj.getClass().getName()); 38 39 System.out.println(obj2.getClass().getName()); 40 41 System.out.println(objs2.getClass().getName()); 42 43 //使用Arrays操做數組 44 System.out.println(Arrays.asList(a4)); 45 } 46 }
第六講:成員方法的反射
一,Method類的瞭解:
ethod
提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法多是類方法或實例方法(包括抽象方法)。Method
對象所表示方法的 Java 語言修飾符。應該使用 Modifier
類對修飾符進行解碼。String
形式返回此 Method
對象表示的方法名稱。Class
對象的數組,這些對象描述了此 Method
對象所表示的方法的形參類型。若是底層方法不帶參數,則返回長度爲 0 的數組。Class
對象,該對象描述了此 Method
對象所表示的方法的正式返回類型。Method
對象表示的底層方法。個別參數被自動解包,以便與基本形參相匹配,基本參數和引用參數都隨需服從方法調用轉換。二,jdk1.4與jdk1.5 invoke 方法的區別:
jdk1.4 public Object invoke(Object obj,Object[] args)
jdk1.5 public Object invoke(Object obj,Object... args) ====注:這是jdk1.5的新特性。可變參數====
三,專家設計模式:
專家模式:誰調用這個數據,就是誰在調用它的專家。
如人關門:
調用者:是門調用關的動做,對象是門,由於門知道如何執行關的動做,經過門軸之類的細節實現。
指揮者:是人在指揮門作關的動做,只是給門發出了關的信號,讓門執行。
總結:變量使用方法,是方法自己知道如何實現執行的過程,也就是「方法對象」調用方法,才執行了方法的每一個細節的。
四,代碼練習:
1 import java.lang.reflect.*; 2 3 public class Reflect_Method { 4 public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 5 6 //定義Method對象,表示String中的charAt方法 7 Method m = String.class.getMethod("charAt", int.class); 8 9 //實例化String對象 10 String str = "abcd"; 11 12 //經過Method對象調用方法 13 System.out.println(m.invoke(str, 1)); 14 15 //jdk1.4 方法調用 16 System.out.println(m.invoke(str, new Object[]{2})); 17 } 18 }
第七講:對接收數組參數的成員方法進行反射
一,練習目標:
寫一個程序實現根據用戶提供的類名去動態的調用它的main() 方法。
二,爲何要使用反射:
在寫源程序時,並不知道使用者傳入的類名是什麼,可是雖然傳入的類名不知道,而知道的是這個類中的方法有main這個方法。因此能夠經過反射的方式,經過使用者傳入的類名(可定義字符串型變量做爲傳入類名的入口,經過這個變量表明類名),內部經過傳入的類名獲取其main方法,而後執行相應的內容。
三,遇到的問題:
經過反射方式來調用這個main方法時,如何爲invoke方法傳遞參數呢?按jdk1.5的語法,整個數組是一個參數,而按jdk1.4的語法,數組中的每一個元素對應一個 參數,當把一個字符串數組做爲參數傳遞給invoke方法時,javac會到底按照哪一種語法進行處理呢?jdk1.5確定要兼容jdk1.4的語法,會按jdk1.4的語法進行處理,即把數組打散成爲若干個單獨的參數。因此,在給main方法傳遞參數時,不能使用代碼mainMethod.invoke(null,new String[]{「xxx」}),javac只把它看成jdk1.4的語法進行理解,而不把它看成jdk1.5的語法解釋,所以會出現參數類型不對的問題。
四,解決辦法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"});
五,代碼練習:
1 import java.lang.reflect.Method; 2 3 4 //定義一個測試類 5 class Test{ 6 public static void main(String[] args){ 7 for(String arg : args){ 8 System.out.println(arg); 9 } 10 } 11 } 12 13 14 //用反射方式根據用戶提供的類名,去執行該類中的main方法。 15 public class PerformedMain{ 16 17 public static void main(String[] args) throws Exception { 18 //普通方式 19 Test.main(new String[]{"123","456","789"}); 20 System.out.println("-----------------------------"); 21 22 //反射方式 23 String className=args[0]; 24 Class clazz=Class.forName(className); 25 26 Method method_Main=clazz.getMethod("main",String[].class); 27 //方式一:強制轉換爲超類Object,不用拆包 28 method_Main.invoke(null, (Object)new String[]{"123","456","789"}); 29 //方式二:將數組打包,編譯器拆包後就是一個String[]類型的總體 30 method_Main.invoke(null, new Object[]{new String[]{"123","456","789"}}); 31 } 32 }
============此示例用eclipse運行時,須要在Run As——>RunConfigurations——>Arguments——>Program arguments中添加要執行的類名,如:Reflect.Test。========
第八講:數組與Object的關係及其反射類型
一,具備相同Class 文件的數組斷定 :具備相同維數和元素類型的數組屬於同一個類型,即具備相同的Class實例對象。數組字節碼的名字:有[和數組對應類型的縮寫,如int[]數組的名稱爲:[I
2、Object[]與String[]沒有父子關係,Object與String有父子關係,因此new Object[]{「aaa」,」bb」}不能強制轉換成new String[]{「aaa」,」bb」}; Object x =「abc」能強制轉換成String x =「abc」。
=======注:全部數組的父類是Object 因此數組類能夠轉換爲Object對象:Object obj = new int[3]; 全部引用類型都是Object 的子類。因此引用類型的數組能夠轉換爲Object的數組: Object obj[] = new String[3];。==========
三,如何獲得某個數組中的某個元素的類型,
例:
int a = new int[3];Object[] obj=new Object[]{」ABC」,1};
沒法獲得某個數組的具體類型,只能獲得其中某個元素的類型,
如:
Obj[0].getClass().getName()獲得的是java.lang.String。
四,Array工具類用於完成對數組的反射操做。
Array.getLength(Object obj);//獲取數組的長度
Array.get(Object obj,int x);//獲取數組中的元素
五,代碼練習:
1 import java.util.Arrays; 2 3 4 public class Reflect_Array { 5 public static void main(String[] args) { 6 7 //分別定義不一樣維數,不一樣類型的數組 8 int[] a1 = new int[]{1,2,3}; 9 int[] a2 = new int[5]; 10 int[][] a3 = new int[2][4]; 11 String[] a4 = new String[]{"a","b","c"}; 12 13 //具備相同維數相同類型的數組是共享一個字節碼對象的 14 System.out.println(a1.getClass() == a2.getClass()); 15 16 //下面這句話編譯期出錯 17 //System.out.println(a1.getClass() == a4.getClass()); 18 19 //獲取數組的字節碼名字即類名 20 System.out.println(a1.getClass().getName()); 21 System.out.println(a4.getClass().getName()); 22 23 //獲取數組的父類名字 24 System.out.println(a4.getClass().getSuperclass().getName()); 25 26 27 //數組是Object的子類,向上轉型 28 Object obj = a1; 29 Object obj2 = a3; 30 31 //下面這個表達式不成立編譯期出錯 32 //Object[] objs = a1; 33 34 //引用類型數組,能夠向父類型數組轉型 35 Object[] objs2 = a4; 36 Object[] objs3 = a3; 37 38 System.out.println(obj.getClass().getName()); 39 40 System.out.println(obj2.getClass().getName()); 41 42 System.out.println(objs2.getClass().getName()); 43 44 //使用Arrays操做數組 45 System.out.println(Arrays.asList(a4)); 46 } 47 }
第九講:數組的反射應用
一,學習目標:
經過Array 類實現對數組的反射操做。
二,Arrays.asList() 方法處理 int[] 和 String[] 的差別:
由於該方法參數定義爲public static <T> List<T> asList(T... a) ,由於String[] 能夠轉換爲Object[] 因此處理它是按照jdk1.5新特性,可變參數處理的,它做爲一個參數傳入。而int[] 因爲不能轉換爲Object[] 因此他的處理是按照jdk1.4的規則做爲多個參數進行處理,即把數組展開了。
三,代碼練習:
1 import java.lang.reflect.Array; 2 3 4 5 public class Reflect_Array2 { 6 public static void main(String[] args) { 7 8 //建立一個數組做爲參數傳入 9 String[] s = new String[]{"abc","d","feg"}; 10 11 //普通對象 12 String str = "lisi"; 13 printObject(s); 14 printObject(str); 15 } 16 17 public static void printObject(Object obj){ 18 if(obj.getClass().isArray()){ 19 int len = Array.getLength(obj); 20 for(int i = 0 ; i<len; i++){ 21 System.out.println(Array.get(obj,i)); 22 } 23 }else{ 24 System.out.println(obj); 25 } 26 } 27 }
第十講:ArrayList_HashSet的比較及Hashcode分析
1、哈希算法的由來:
若在一個集合中查找是否含有某個對象,一般是一個個的去比較,找到後還要進行equals的比較,對象特別多時,效率很低。有這麼一種HashCode算法,有一個集合,把這個集合分紅若干個區域,每一個存進來的對象,能夠算出一個hashCode值,根據算出來的值,就放到相應的區域中去。當要查找某一個對象,只要算出這個對象的hashCode值,看屬於第幾個區域,而後到相應的區域中去尋找,看是否有與此對象相等的對象。這樣查找的性能就提升了。
2、要想HashCode方法有價值的話,前提是對象存入的是hash算法這種類型的集合當中纔有價值。若是不存入是hashCode算法的集合中,則不用複寫此方法。
3、若是沒有複寫hashCode方法,對象的hashCode值是按照內存地址進行計算的。這樣即便兩個對象的內容是想等的,可是存入集合中的內存地址值不一樣,致使hashCode值也不一樣,被存入的區域也不一樣。因此兩個內容相等的對象,就能夠存入集合中。
因此就有這樣的說法:若是兩個對象equals相等的話,你應該讓他們的hashCode也相等。若是對象存入的不是根據hash算法的集合中,就不須要複寫hashCode方法。
4、當一個對象存儲進HashSet集合中之後,就不能修改這個對象中的那些參與計算哈希值的字段了,不然對象修改後的哈希值與最初存儲進HashSet集合中的哈希值就不一樣了。在這種狀況下,調用contains方法或者remove方法來尋找或者刪除這個對象的引用,就會找不到這個對象。從而致使沒法從HashSet集合中單獨刪除當前對象,從而形成內存泄露。
五,代碼練習:
1 import java.util.*; 2 3 public class HashCodeDemo { 4 public static void main(String[] args) { 5 6 HashCodeTest h1 = new HashCodeTest(4,4); 7 HashCodeTest h2 = new HashCodeTest(4,4); 8 HashCodeTest h3 = new HashCodeTest(5,5); 9 10 Collection collections = new HashSet(); 11 12 collections.add(h1); 13 collections.add(h2); 14 collections.add(h3); 15 System.out.println(collections.size()); 16 } 17 } 18 19 class HashCodeTest{ 20 private int x; 21 private int y; 22 23 24 public HashCodeTest(int x, int y) { 25 this.x = x; 26 this.y = y; 27 } 28 29 30 @Override 31 public int hashCode() { 32 final int prime = 31; 33 int result = 1; 34 result = prime * result + x; 35 result = prime * result + y; 36 return result; 37 } 38 39 40 @Override 41 public boolean equals(Object obj) { 42 if (this == obj) 43 return true; 44 if (obj == null) 45 return false; 46 if (getClass() != obj.getClass()) 47 return false; 48 HashCodeTest other = (HashCodeTest) obj; 49 if (x != other.x) 50 return false; 51 if (y != other.y) 52 return false; 53 return true; 54 } 55 56 57 }