java反射主要從如下幾個方面理解php
Java程序在運行時,Java運行時系統一直對全部的對象進行所謂的運行時類型標識,即所謂的RTTI。這項信息紀錄了每一個對象所屬的類。虛擬機一般使用運行時類型信息選準正確方法去執行,用來保存這些類型信息的類是Class類。Class類封裝一個對象和接口運行時的狀態,當裝載類時,Class類型的對象自動建立。
簡單解釋上面一段話
一、Class類也是類的一種,只是名字和class關鍵字高度類似。Java是大小寫敏感的語言。
二、Class類的對象內容是你建立的類的類型信息,好比你建立一個shapes類,那麼,Java會生成一個內容是shapes的Class類的對象。
三、Class類的對象不能像普通類同樣,以 new shapes() 的方式建立,它的對象只能由JVM建立,由於這個類沒有public構造函數。
四、Class類的做用是運行時提供或得到某個對象的類型信息。java
全部java類都是繼承了object這個類,在object這個類中有一個方法:getclass().這個方法是用來取得該類已經被實例化了的對象的該類的引用,這個引用指向的是Class類的對象。python
一、Class類的forName方法bootstrap
Class<?> aClass = Class.forName("com.sl.reflect.Student");
二、對象的getClass()方法數組
Student student = new Student(); Class<? extends Student> aClass1 = student.getClass();
三、使用類名加.class函數
Class classes = Student.class.getClass();
四、經過ClassLoader對象的loadClass()方法測試
Class<?> aClass2 = ClassLoader.getSystemClassLoader().loadClass("com.sl.reflect.Student");
敲黑板調用newInstance()方法時,調用的是無參構造器,因此每一個類中必定要聲明一個無參構造器ui
類裝載器是用來把類(class)裝載進 JVM 的。JVM 規範定義了兩種類型的類裝載器:啓動類裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)。 JVM在運行時會產生3個類加載器組成的初始化加載器層次結構 ,以下圖所示:this
//一、獲取系統類的加載器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println(classLoader); //2. 獲取系統類加載器的父類加載器(擴展類加載器,能夠獲取). classLoader = classLoader.getParent(); System.out.println(classLoader); //3. 獲取擴展類加載器的父類加載器(引導類加載器,不可獲取). classLoader = classLoader.getParent(); System.out.println(classLoader);
注意系統類加載器能夠加載當前項目src目錄下面的全部類,若是文件也放在src下面,也能夠用類加載器來加載調用 getResourceAsStream 獲取類路徑下的文件對應的輸入流。spa
//文件夾在src下 InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("text1.txt"); //文件夾在包名下 InputStream resourceAsStream1 = ClassLoader.getSystemClassLoader().getResourceAsStream("com/sl/reflect/text2.txt");
Java反射機制主要提供瞭如下功能
Student測試類
/** * @author shuliangzhao * @Title: Student * @ProjectName design-parent * @Description: TODO * @date 2019/6/15 23:08 */ public class Student { private String name; private Integer age; public Student() { } public Student(String name,Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
public static void testMethod() throws Exception { Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1.獲取方法 // 獲取取clazz對應類中的全部方法--方法數組(一) // 不能獲取private方法,而且獲取從父類繼承來的全部方法 Method[] methods = aClass.getMethods(); for (Method method:methods) { System.out.println(method); } System.out.println("================================"); //2.獲取方法 // 獲取取clazz對應類中的全部方法--方法數組(一) // 不能獲取private方法,不獲取從父類繼承來的全部方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method method:declaredMethods) { System.out.println(method); } System.out.println("================================="); // 1.3.獲取指定的方法 // 須要參數名稱和參數列表,無參則不須要寫 // 對於方法public void setName(String name) { } Method method = aClass.getDeclaredMethod("setName", String.class); System.out.println(method); // 而對於方法public void setAge(int age) { } method = aClass.getDeclaredMethod("setAge", Integer.class); System.out.println(method); // 這樣寫是獲取不到的,若是方法的參數類型是int型 // 若是方法用於反射,那麼要麼int類型寫成Integer: public void setAge(Integer age) { } // 要麼獲取方法的參數寫成int.class //2.執行方法 // invoke第一個參數表示執行哪一個對象的方法,剩下的參數是執行方法時須要傳入的參數 Object obje = aClass.newInstance(); method.invoke(obje,2); //若是一個方法是私有方法,第三步是能夠獲取到的,可是這一步卻不能執行 //私有方法的執行,必須在調用invoke以前加上一句method.setAccessible(true); } /** * 把類對象和類方法名做爲參數,執行方法 * * 把全類名和方法名做爲參數,執行方法 * 可變參數能夠放數組 * @param obj: 方法執行的那個對象. * @param methodName: 類的一個方法的方法名. 該方法也多是私有方法. * @param args: 調用該方法須要傳入的參數 * @return: 調用方法後的返回值 * */ public Object invoke(Object obj, String methodName, Object ... args) throws Exception{ //1. 獲取 Method 對象 // 由於getMethod的參數爲Class列表類型,因此要把參數args轉化爲對應的Class類型。 Class [] parameterTypes = new Class[args.length]; for(int i = 0; i < args.length; i++){ parameterTypes[i] = args[i].getClass(); System.out.println(parameterTypes[i]); } Method method = obj.getClass().getDeclaredMethod(methodName, parameterTypes); //若是使用getDeclaredMethod,就不能獲取父類方法,若是使用getMethod,就不能獲取私有方法 // //2. 執行 Method 方法 //3. 返回方法的返回值 return method.invoke(obj, args); }
public static void testField() throws Exception { Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1.獲取字段 // 1.1 獲取全部字段 -- 字段數組 // 能夠獲取公用和私有的全部字段,但不能獲取父類字段 Field[] declaredFields = aClass.getDeclaredFields(); for (Field field:declaredFields) { System.out.println(field); } System.out.println("============================="); // 1.2獲取指定字段 Field field = aClass.getDeclaredField("name"); System.out.println(field.getName()); System.out.println("=============================="); Student student = new Student(); //若是字段是私有的,無論是讀值仍是寫值,都必須先調用setAccessible(true)方法 field.setAccessible(true); student.setAge(1); student.setName("張三"); //2.使用字段 // 2.1獲取指定對象的指定字段的值 Object o = field.get(student); System.out.println(o); System.out.println("=========================="); // 2.2設置指定對象的指定對象Field值 field.set(student, "DEF"); System.out.println(student.getName()); }
public static void testConstructor() throws Exception{ Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1. 獲取 Constructor 對象 // 1.1 獲取所有 Constructor<?>[] constructors = aClass.getConstructors(); for (Constructor constructor:constructors) { System.out.println(constructor); } System.out.println("============================"); // 1.2獲取某一個,須要參數列表 Constructor<Student> constructor = aClass.getConstructor(String.class, Integer.class); System.out.println(constructor); System.out.println("============================"); //2. 調用構造器的 newInstance() 方法建立對象 Object obj = constructor.newInstance("zhagn", 1); }
@Retention(RetentionPolicy.RUNTIME) @Target(value={ElementType.METHOD}) public @interface AgeValidator { public int min(); public int max(); } public static void testAnnotation() throws Exception{ Class<?> aClass = Class.forName("com.sl.reflect.Student"); Object o = aClass.newInstance(); Method method = aClass.getDeclaredMethod("setAge", Integer.class); int val = 6; AgeValidator annotation = method.getAnnotation(AgeValidator.class); if (annotation != null) { if (annotation instanceof AgeValidator) { AgeValidator ageValidator = annotation; if (val < ageValidator.min() || val > ageValidator.max()) { throw new RuntimeException("年齡非法"); } } } method.invoke(o,20); System.out.println(o); }