目錄:
1)java反射機制概述
2)理解Class類並獲取Class實例
3)類的加載與ClassLoader
4)創建運行時類的對象
5)獲取運行時類的完整結構
6)調用運行時類的指定結構
一---基本概念
Java的反射(reflection)機制是指在程序的運行狀態中,可以構造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法(即使是private的),可以調用任意一個對象的屬性和方法。這種動態獲取程序信息以及動態調用對象的功能稱為Java語言的反射機制。反射被視為動態語言的關鍵(來自 百度百科)。
一句話概述就是利用反射,底褲都能扒出來。
游戲外掛的原理:游戲在運行的時候,通過反射去改變運行時的參數,從而達到作弊的目的。
正常方式:引入需要的包類名稱->通過new實例化->取得實例化對象
反射方式:實例化對象->getClass()方法->得到完整的包類名稱
加載完類之后,在堆內存的方法區中就產生了一個Class類型的對象,通過這個對象我們可以看到類的結構。
1 package reflection; 2 3 4 public class test01 extends Object{ 5 public static void main(String[] args) throws ClassNotFoundException{ 6 // 通過反射獲取類的class對象 7 Class c1 = Class.forName("reflection.user"); 8 System.out.println(c1); 9 Class c2 = Class.forName("reflection.user"); 10 Class c3 = Class.forName("reflection.user"); 11 Class c4 = Class.forName("reflection.user"); 12 13 // 一個類在內存中只有一個class對象 14 // 一個類被加載后,類的整個結構都會被封裝在class對象中 15 System.out.println(c2.hashCode()); 16 System.out.println(c3.hashCode()); 17 System.out.println(c4.hashCode()); 18 19 } 20 } 21 22 // 實體類 23 class user { 24 private String name; 25 private int id; 26 private int age; 27 28 public user() { 29 } 30 31 public user(String name, int id, int age) { 32 this.name = name; 33 this.id = id; 34 this.age = age; 35 } 36 37 public String getName() { 38 return name; 39 } 40 41 public void setName(String name) { 42 this.name = name; 43 } 44 45 public int getId() { 46 return id; 47 } 48 49 public void setId(int id) { 50 this.id = id; 51 } 52 53 public int getAge() { 54 return age; 55 } 56 57 public void setAge(int age) { 58 this.age = age; 59 } 60 61 @Override 62 public String toString() { 63 return "user{" + 64 "name='" + name + '\'' + 65 ", id=" + id + 66 ", age=" + age + 67 '}'; 68 } 69 }
運行結果:無論創建多少個對象,Class的類型都只有一個
反射的優缺點
1)優點:可以動態創建對象和編譯,靈活性大
2)缺點:對性能有影響,我們告訴虛擬機我們要做什么,讓他去干,命令下達和他完成完有一個時間延遲。直接new出來的和反射出來的差了好幾十倍。
反射主要的API:
1)java.lang.Class:代表一個類 (記住這個)
2)java.lang.reflect.Method: 代表類的方法
3)java.lang.reflect.Field:代表類的成員變量
4)java.lang.reflect.Constructor:代表類的構造器
Class類:
在Object類中定義了以下的方法,此方法將被所有子類繼承
1 public final native Class getClass();
1)Class本身也是一個類
2)Class對象只能由系統建立對象
3)一個加載的類在JVM中只會有一個Class實例
4)一個Class對象對應的是一個加載到JVM中的一個class文件
5)每個類的實例都會記得自己是由哪個Class實例所生成
6)通過Class可以完整的得到一個類中的所有被加載的結構
7)Class是reflection的根源,針對任何你想動態加載,運行的類,唯有先獲得相應的Class對象
Class類的常用方法:
獲取Class類的實例:
1)若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程序性能最高
Class clazz = Person.class
2)已知某個類的實例,調用該實例的getClass()方法獲取Class()對象
Class clazz = person.getClass()
3)已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取,
可能拋出ClassNotFoundException
class clazz = Class.forName("demo01.Studengt")
4)內置基本數據類型可以 直接用類名.Type
測試代碼:
1 package reflection; 2 3 public class test02 { 4 public static void main(String[] args) throws ClassNotFoundException { 5 Person person = new Student(); 6 System.out.println("這個人是" + person.name); 7 // 方式一: 通過對象獲得 8 Class c1 = person.getClass(); 9 System.out.println(c1.hashCode()); 10 11 12 // 方式二: forName獲得 13 Class c2 = Class.forName("reflection.Student"); 14 System.out.println(c2.hashCode()); 15 16 // 方式三: 通過類名.class獲得 17 Class c3 = Student.class; 18 System.out.println(c3.hashCode()); 19 20 // 方式四: 基本內置類型的包裝類都有一個Type屬性 21 Class c4 = Float.TYPE; 22 System.out.println(c4); 23 24 // 獲得父類的類型(這里就是通過對象獲取類) 25 Class c5 = c1.getSuperclass(); 26 System.out.println(c5); 27 28 } 29 } 30 31 class Person { 32 String name; 33 int age; 34 35 public Person() { 36 } 37 38 public Person(String name, int age) { 39 this.name = name; 40 this.age = age; 41 } 42 43 } 44 45 class Student extends Person { 46 public Student() { 47 this.name = "學生"; 48 } 49 } 50 51 class Teacher extends Person { 52 public Teacher() { 53 this.name = "老師"; 54 } 55 }
結果: