Java的反射機制
阿新 • • 發佈:2020-07-21
一、Java的反射概述
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;
這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法,所以先要獲取到每一個位元組碼檔案對應的Class型別的物件
新建Class類進行測試:
package com.hansun.entity; public class Person { public String name; public intage; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String show(){ return "name:"+name+", age :"+age; } }
package com.hansun.entity; public class Student extends Person { public String className;private String address; public Student() { super(); } private Student(String name, int age, String className) { super(name, age); this.className = className; } public Student(String name, int age, String className, String address) { super(name, age);this.className = className; this.address = address; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } private void add(int a, int b) { System.out.println(a + b); } @Override public String toString() { return "Student{" + "className='" + className + '\'' + ", address='" + address + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; } }
二、獲取反射的方式
// 通過Class類中的靜態方法forName,直接獲取到一個類的位元組碼檔案物件,此時該類還是原始檔階段,並沒有變為位元組碼檔案。 1、Class clazz1 = Class.forName("全限定類名"); //當類被載入成.class檔案時,此時Person類變成了.class,在獲取該位元組碼檔案物件,也就是獲取自己, 該類處於位元組碼階段。 2、Class clazz2 = Person.class; //通過類的例項獲取該類的位元組碼檔案物件,該類處於建立物件階段 3、Class clazz3 = p.getClass();
驗證三種方式獲取的Class物件是否同一個
/** * 測試三種反射得來的Class物件 是否是同一個 */ private static void testClass() throws ClassNotFoundException { // 第一種方式獲取Class物件 // new 產生一個Student物件,一個Class物件。 Student stu1 = new Student(); //獲取Class物件 Class stuClass = stu1.getClass(); System.out.println(stuClass.getName()); // 第二種方式獲取Class物件 Class stuClass2 = Student.class; // 判斷第一種方式獲取的Class物件和第二種方式獲取的是否是同一個 System.out.println(stuClass == stuClass2); // 第三種方式獲取Class物件 // 注意此字串必須是真實路徑,就是帶包名的類路徑,包名.類名 Class stuClass3 = Class.forName("com.hansun.entity.Student"); // 判斷三種方式是否獲取的是同一個Class物件 System.out.println(stuClass3 == stuClass2); }
三、獲取類Class物件中成員變數Field欄位
private static void testField() throws Exception { Class cls = Class.forName("com.hansun.entity.Student"); //獲取成員變數,包括子類及父類,同時只能包含公共的方法 Field[] fields = cls.getFields(); for (Field field : fields) { System.out.print(field + "\t"); System.out.print(field.getModifiers() + "\t"); System.out.print(field.getType() + "\t"); System.out.print(field.getName() + "\t"); System.out.println(); } System.out.println("========================"); //此方法返回的是當前類的所有屬性,不僅僅侷限於公共訪問修飾符,所有的訪問修飾符都可以拿到 Field[] declaredFields = cls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.print(declaredField + "\t"); System.out.print(declaredField.getModifiers() + "\t"); System.out.print(declaredField.getType() + "\t"); System.out.println(declaredField.getName()); } System.out.println("========================"); // 反射在一定程度上破壞了封裝性,需要合理使用 Field address = cls.getDeclaredField("address"); // 設定該屬性是否能被訪問,true表示能被訪問,破壞了封裝性 address.setAccessible(true); System.out.println(address.getName()); Object o = cls.newInstance(); address.set(o, "北京市"); System.out.println(((Student) o).getAddress()); System.out.println("========================"); }
四、獲取類Class物件中method方法
private static void testMethod() throws Exception { Class cls = Class.forName("com.hansun.entity.Student"); // 獲取該物件的普通方法,包含的方法範圍是當前物件及父類物件的所有公共方法 Method[] methods = cls.getMethods(); for (Method method : methods) { System.out.print(method.getModifiers() + "\t"); System.out.print(method.getName() + "\t"); System.out.println(Arrays.toString(method.getParameterTypes())); } System.out.println("-----------------------"); // 獲取當前類中所有的方法,無論什麼訪問修飾符 Method[] declaredMethods = cls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.print(declaredMethod.getModifiers() + "\t"); System.out.print(declaredMethod.getName() + "\t"); System.out.println(Arrays.toString(declaredMethod.getParameterTypes())); } System.out.println("-----------------------"); Method add = cls.getDeclaredMethod("add", int.class, int.class); cls.getDeclaredMethods(); add.setAccessible(true); Object o1 = cls.newInstance(); add.invoke(o1, 123, 87); Method setAddress = cls.getDeclaredMethod("setAddress", String.class); setAddress.invoke(o1, "上海市!"); System.out.println(o1.toString()); }
五、獲取類Class物件中的Constructor構造器
private static void testConstructor() throws Exception { Class cls = Class.forName("com.hansun.entity.Student"); // 獲取物件的所有構造方法,只能獲取公有的改造方法 Constructor[] constructors = cls.getConstructors(); for (Constructor constructor : constructors) { System.out.print(constructor.getModifiers() + "\t"); System.out.println(constructor.getName()); } System.out.println("========================"); // 獲取所有的構造方法,無論是私有還是公有 Constructor[] declaredConstructors = cls.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.print(declaredConstructor.getModifiers() + "\t"); System.out.print(declaredConstructor.getName() + "\t"); // 獲取構造器中方法簽名 System.out.print(Arrays.toString(declaredConstructor.getParameterTypes()) + "\t"); System.out.println(declaredConstructor.getParameterCount() + "\t"); } // 如何呼叫私有的構造方法呢? Constructor<Student> declaredConstructor = cls.getDeclaredConstructor(String.class, int.class, String.class); declaredConstructor.setAccessible(true); Student o2 = declaredConstructor.newInstance("sunhan", 23, "aaaaaaaaaaa"); System.out.println(o2); }