Class 類
對象照鏡子后可以得到的信息:某個類的屬性、方法和構造器、某個類到底實現了哪些接
口。對於每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。一個 Class 對象包含
了特定某個結構(class/interface/enum/annotation/primitive type/void/[])的有關信息。
Class本身也是一個類
Class 對象只能由系統建立對象
一個加載的類在 JVM 中只會有一個Class實例
一個Class對象對應的是一個加載到JVM中的一個.class文件
每個類的實例都會記得自己是由哪個 Class 實例所生成
通過Class可以完整地得到一個類中的所有被加載的結構
Class類是Reflection的根源,針對任何你想動態加載、運行的類,唯有先獲得相應的
Class對象
//反射之前,對於Person的操作 @Test public void test1() { //1.創建Person類的對象 Person p1 = new Person("Tom", 12); //2.通過對象,調用其內部的屬性、方法 p1.age = 10; System.out.println(p1.toString()); p1.show(); //在Person類外部,不可以通過Person類的對象調用其內部私有結構。 //比如:name、showNation()以及私有的構造器 }
//反射之后,對於Person的操作 @Test public void test2() throws Exception{ Class clazz = Person.class; //1.通過反射,創建Person類的對象 Constructor cons = clazz.getConstructor(String.class,int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person) obj; System.out.println(p.toString()); //2.通過反射,調用對象指定的屬性、方法 //調用屬性 Field age = clazz.getDeclaredField("age"); age.set(p,10); System.out.println(p.toString()); //調用方法 Method show = clazz.getDeclaredMethod("show"); show.invoke(p); System.out.println("*******************************"); //通過反射,可以調用Person類的私有結構的。比如:私有的構造器、方法、屬性 //調用私有的構造器 Constructor cons1 = clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1 = (Person) cons1.newInstance("Jerry"); System.out.println(p1); //調用私有的屬性 Field name = clazz.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"HanMeimei"); System.out.println(p1); //調用私有的方法 Method showNation = clazz.getDeclaredMethod("showNation", String.class); showNation.setAccessible(true); String nation = (String) showNation.invoke(p1,"中國");//相當於String nation = p1.showNation("中國") System.out.println(nation); }
//疑問1:通過直接new的方式或反射的方式都可以調用公共的結構,開發中到底用那個? //建議:直接new的方式。 //什么時候會使用:反射的方式。 反射的特征:動態性 //疑問2:反射機制與面向對象中的封裝性是不是矛盾的?如何看待兩個技術? //不矛盾。 /* 關於java.lang.Class類的理解 1.類的加載過程: 程序經過javac.exe命令以后,會生成一個或多個字節碼文件(.class結尾)。 接着我們使用java.exe命令對某個字節碼文件進行解釋運行。相當於將某個字節碼文件 加載到內存中。此過程就稱為類的加載。加載到內存中的類,我們就稱為運行時類,此 運行時類,就作為Class的一個實例。 2.換句話說,Class的實例就對應着一個運行時類。 3.加載到內存中的運行時類,會緩存一定的時間。在此時間之內,我們可以通過不同的方式 來獲取此運行時類。 */ //獲取Class的實例的方式(前三種方式需要掌握) @Test public void test3() throws ClassNotFoundException { //方式一:調用運行時類的屬性:.class Class clazz1 = Person.class; System.out.println(clazz1); //方式二:通過運行時類的對象,調用getClass() Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2); //方式三:調用Class的靜態方法:forName(String classPath) Class clazz3 = Class.forName("com.atguigu.java.Person"); // clazz3 = Class.forName("java.lang.String"); System.out.println(clazz3); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); //方式四:使用類的加載器:ClassLoader (了解) ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.atguigu.java.Person"); System.out.println(clazz4); System.out.println(clazz1 == clazz4); }
//萬事萬物皆對象?對象.xxx,File,URL,反射,前端、數據庫操作 //Class實例可以是哪些結構的說明: @Test public void test4(){ Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int[][].class; Class c5 = ElementType.class; Class c6 = Override.class; Class c7 = int.class; Class c8 = void.class; Class c9 = Class.class; int[] a = new int[10]; int[] b = new int[100]; Class c10 = a.getClass(); Class c11 = b.getClass(); // 只要數組的元素類型與維度一樣,就是同一個Class System.out.println(c10 == c11); }