Class對象和反射
1.class對象
在java中一切都是對象,從某種意義上,java中的對象可以分為:實例對象和Class對象。實例對象通過new關鍵得到,那麽Class對象呢?Class對象無法通過new關鍵字獲取,在類加載的過程中,JVM生成一個與加載的字節碼文件相關的class對象。通過類名可以獲取對應Class對象。class對象主要用來對應類的所有對象。java程序在運行之前並未完全加載,各個類只在需要的時候才將該類加載進內存,生成對應的class對象。
所有的類都是在對其第一次使用的時候,動態加載到JVM中,當程序創建第一個對類靜態成員的引用的時候,就會加載這個。使用new創建類的對象的也會被當做是對類靜態成員的引用。因此java程序在它開始運行之前並非被完全加載,其各個部分是在必須的時候才加載。一旦某個類的Class對象被載入內存,它就用來創建這個類的所有的對象。如下面程序所示:
1 class Test1{ 2 static{ 3 System.out.println("loading1"); 4 } 5 6 } 7 class Test2{ 8 static{ 9 System.out.println("loading2"); 10 } 11 12 } 13 class Test3{ 14 static{ 15 System.out.println("loading3"); 16 } 17 18 } 19 public classDemo { 20 public static void main(String[] args) { 21 //new Test1(); 22 Class clz = Test1.class;//註意Class clz = Test1.class;,不會觸發靜態塊的執行,即不會自動初始化該Class對象 23 try { 24 25 Class.forName("Test2"); 26 } catch (ClassNotFoundException e) { 27 e.printStackTrace();28 } 29 new Test3(); 30 } 31 32 }
輸出結果:
loading1
loading2
loading3
2.Class對象的獲取
Class對象是jvm用來保存對象實例對象的相關信息的,除此之外,我們完全可以把Class對象看成一般的實例對象,事實上所有的Class對象都是類Class的實例。獲取Class對象主要有三種方式:
1 /** 2 * 獲取Class對象的三種方式 3 */ 4 public class Demo{ 5 public static void main(String[] args){ 6 //1.通過實例對象獲取class對象 7 Demo demo = new Demo(); 8 Class clsdemo = demo.getClass(); 9 10 //2.通過Class的靜態方法forName 11 try { 12 Class clsdemo2 = Class.forName("Demo"); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 17 //3.通過類名和class關鍵字獲取 18 Class clsdemo3 = Demo.class; 19 } 20 }
3.Class對象的使用和反射
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。通過反射機制來訪問一個類java對象的屬性,方法,甚至我們可以輕易改變一個私有成員。java反射是基於Class類和java.lang.Reflect類庫。反射機制使得我們可以創建一個編譯時完全未知的對象,並調用這個對象的方法。
1 public class Demo{ 2 public static void main(String[] args){ 3 4 Test test = new Test(); 5 System.out.println(test.getClass()==Test.class);//一個類對應的class對象在內存中是唯一的 6 7 Class cls = Test.class;//字節碼文件加載進內存,生成class對象,但是不會進行相關的初始化工作,不引起靜態塊的執行 8 try { 9 10 Field [] fields = cls.getDeclaredFields(); 11 for (Field field : fields) { 12 System.out.println(field); 13 } 14 Method [] methods = cls.getDeclaredMethods(); 15 for (Method method : methods) { 16 System.out.println(method); 17 } 18 } catch (SecurityException e) { 19 e.printStackTrace(); 20 } 21 } 22 } 23 class Test{ 24 public static int count=0; 25 private int age=20; 26 public String name="xm"; 27 static{ 28 System.out.println("類被加載"); 29 } 30 public void test(){ 31 System.out.println("sss"); 32 } 33 private void call(){ 34 System.out.println("hi"); 35 } 36 }
類被加載 true public static int com.test.demo.Test.count private int com.test.demo.Test.age public java.lang.String com.test.demo.Test.name public void com.test.demo.Test.test() private void com.test.demo.Test.call()
4.泛化的Class引用
Class引用總是指向某個Class對象,它可以制造實例,並包含可以作用於這些實例的所有方法代碼,且包含該類的靜態成員,因此Class引用表示的就是它指向的對象的確切類型,而該對象便是Class類的一個對象。class引用可泛化。通過泛型語法,可以讓編譯器強制的執行額外的類型檢查。如果希望放松些限制,可以使用通配符?,表示“任何事物”,如Class<?> intClass = int.class;在java SE5中,Class<?>優於平凡的Class.如下:
public class Demo { public static void main(String[] args) { Class intClass = int.class; Class<Integer> integerClass = int.class; integerClass = Integer.class;
Class<?> integerClz = Integer.class;
} }
Class對象和反射