反射機制有什麼用?java
反射機制的相關類在java.lang.reflect.*;
包下。數組
反射機制相關的重要的類有哪些?安全
java.lang.Class
:表明整個字節碼,表明一個類型,表明整個類。工具
java.lang.reflect.Method
:表明字節碼中的方法字節碼。表明類中的方法。測試
java.lang.reflect.Constructor
:表明字節碼中的構造方法字節碼。表明類中的構造方法this
java.lang.reflect.Field
:表明字節碼中的屬性字節碼。表明類中的成員變量(靜態變量+實例變量)。spa
java.lang.Class
:翻譯
public class User{ // Field int no; // Constructor public User(){ } public User(int no){ this.no = no; } // Method public void setNo(int no){ this.no = no; } public int getNo(){ return no; } }
```
java.lang.Class
實例的三種方式。
Class c = Class.forName("完整類名帶包名")
。Class c = 對象.getClass();
Class c = 任何類型.class;
public class ReflectTest01 { public static void main(String[] args) { /* Class.forName() 1.靜態方法 2.方法的參數是一個字符串 3.字符串須要的是一個完整的類名 4.完整類名必須帶有包名。java.lang包也不能省。 */ Class c1 = null; Class c2 = null; try { c1 = Class.forName("java.lang.String");//c1表明String.class文件,或者說C1表明String類型 c2 = Class.forName("java.util.Date");//c2表明Date類型 Class c3 = Class.forName("java.lang.Integer");//c3表明Integer類型 Class c4 = Class.forName("java.lang.System");//c4表明System類型 } catch (ClassNotFoundException e) { e.printStackTrace(); } // Java中任何一個對象都有一個方法:getClass() String s = "abc"; Class x = s.getClass();//x表明String.class字節碼文件,x表明String類型 System.out.println(c1 == x);//true (==判斷的是對象的內存地址) Date time = new Date(); Class y = time.getClass(); System.out.println(c2 == y);//true(c2和y兩個變量中保存的內存地址都是同樣的,都指向方法區中的字節碼文件) // 第三種方式,Java語言中任何一種類型,包括基本數據類型,它都有.class屬性。 Class z = String.class;//z表明String類型 Class k = Date.class;//k表明Date類型 Class f = int.class;//f表明int類型 Class e = double.class;//e表明double類型 System.out.println(x == z);//true } }
Class
的newInstance()
方法來實例化對象newInstance()
方法內部實際上調用了無參數構造方法,必須保證無參構造存在才能夠。public class ReflectTest02 { public static void main(String[] args) { // 這是不使用反射機制建立對象 User user = new User(); System.out.println(user); // 下面這段代碼是以反射機制的方式建立對象。 try { // 經過反射機制,獲取Class,經過Class來實例化對象。 Class c = Class.forName("com.yang.javaSE進階.反射.bean.User");//c表明User類型 // newInstance()這個方法會調用User這個類的無參數構造方法,完成對象的建立 // 重點是:newInstance()調用的是無參構造,必須保證無參構造器是存在的 Object obj = c.newInstance(); System.out.println(obj); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }
public class User { public User() { System.out.println("無參構造方法!"); } }
Class.forName("完整類名");
這個方法的執行會致使類加載,類加載時,靜態代碼塊執行。public class ReflectTest03 { public static void main(String[] args) { try { // Class.forName()這個方法的執行會致使類加載 Class.forName("com.yang.javaSE進階.反射.bean.MyClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
public class MyClass{ // 靜態代碼塊在類加載時執行,而且只執行一次。 static{ System.out.println("MyClass類的靜態代碼塊執行了!"); } }
ClassLoader
rt.jar
ext/*.jar
classpath
String s = "abc";
String.class
文件,找到就加載,那麼是怎麼進行加載的呢?
C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar
。rt.jar
中都是JDK最核心的類庫。C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar
classpath
中的類。public class ReflectTest04 { public static void main(String[] args) throws Exception { // 獲取整個類 Class studentClass = Class.forName("com.yang.javaSE進階.反射.bean.Student"); // 獲取類中全部的Field Field[] fields = studentClass.getFields(); System.out.println(fields.length);//測試數組中只有一個元素 // 取出這個Field Field f = fields[0]; // 取出這個Field的名字 String fieldName = f.getName(); System.out.println(fieldName); // 獲取全部的Field Field[] fs = studentClass.getDeclaredFields(); System.out.println(fs.length); // 遍歷 for (Field field : fs) { // 獲取屬性的修飾符 int i = field.getModifiers();//返回的修飾符是一個數字,每一個數字是修飾符的代號! System.out.println(i); // 能夠將這個「代號」數字轉換成「字符串」 String modifierString = Modifier.toString(i); System.out.println(modifierString); // 獲取屬性的類型 Class fieldType = field.getType(); // String fName = fieldType.getName(); String fName = fieldType.getSimpleName(); System.out.println(fName); // 獲取屬性的名字 System.out.println(field.getName()); } } }
public class Student { // Field翻譯爲字段,其實就是屬性/成員 // 4個Field,分別使用了不一樣的訪問控制權限修飾符 public int no; private String name; protected int age; boolean sex; public static final double MATH_PI = 3.1415926; }