java 反射 Constructor、Method、Field 基本用法
java反射主要從以下幾個方面理解
- 理解 Class 類
- 理解 Java 的類加載機制
- 學會使用 ClassLoader 進行類加載
- 理解反射的機制
- 掌握 Constructor、Method、Field 類的用法
- 理解并掌握動態代理
1、理解Class類
Java程序在運行時,Java運行時系統一直對所有的對象進行所謂的運行時類型標識,即所謂的RTTI。這項信息紀錄了每個對象所屬的類。虛擬機通常使用運行時類型信息選準正確方法去執行,用來保存這些類型信息的類是Class類。Class類封裝一個對象和接口運行時的狀態,當裝載類時,Class類型的對象自動創建。
簡單解釋上面一段話
1、Class類也是類的一種,只是名字和class關鍵字高度相似。Java是大小寫敏感的語言。
2、Class類的對象內容是你創建的類的類型信息,比如你創建一個shapes類,那么,Java會生成一個內容是shapes的Class類的對象。
3、Class類的對象不能像普通類一樣,以 new shapes() 的方式創建,它的對象只能由JVM創建,因為這個類沒有public構造函數。
4、Class類的作用是運行時提供或獲得某個對象的類型信息。
Class原理
所有java類都是繼承了object這個類,在object這個類中有一個方法:getclass().這個方法是用來取得該類已經被實例化了的對象的該類的引用,這個引用指向的是Class類的對象。
怎么獲取Class對象
1、Class類的forName方法
Class<?> aClass = Class.forName("com.sl.reflect.Student");2、對象的getClass()方法
Student student = new Student();Class<? extends Student> aClass1 = student.getClass();3、使用類名加.class
Class classes = Student.class.getClass();4、通過ClassLoader對象的loadClass()方法
Class<?> aClass2 = ClassLoader.getSystemClassLoader().loadClass("com.sl.reflect.Student");Class類的常用方法
image.png
敲黑板調用newInstance()方法時,調用的是無參構造器,所以每個類中一定要聲明一個無參構造器
ClassLoader加載
類裝載器是用來把類(class)裝載進 JVM 的。JVM 規范定義了兩種類型的類裝載器:啟動類裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)。 JVM在運行時會產生3個類加載器組成的初始化加載器層次結構 ,如下圖所示:
?
image.png
//1、獲取系統類的加載器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 獲取類路徑下的文件對應的輸入流。
//文件夾在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;} }Method類
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);}Field類
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());}Constructor類
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);}Annotation
@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);}小結
封裝了描述方法的 Method,
描述字段的 Filed,
描述構造器的 Constructor 等屬性.
2.1 Person.class
2.2 person.getClass()
2.3 Class.forName("com.atguigu.javase.Person")
3.1 如何獲取 Method:
1). getDeclaredMethods: 得到 Method 的數組.
2). getDeclaredMethod(String methondName, Class ... parameterTypes)
3.2 如何調用 Method
1). 如果方法時 private 修飾的, 需要先調用 Method 的 setAccessible(true), 使其變為可訪問
2). method.invoke(obj, Object ... args);
4.1 如何獲取 Field: getField(String fieldName)
4.2 如何獲取 Field 的值:
1). setAccessible(true)
2). field.get(Object obj)
4.3 如何設置 Field 的值:
field.set(Obejct obj, Object val)
6.1 getGenericSuperClass: 獲取帶泛型參數的父類
6.2 Type 的子接口: ParameterizedType
6.3 可以調用 ParameterizedType 的 Type[] getActualTypeArguments() 獲取泛型參數的數組.
總結
以上是生活随笔為你收集整理的java 反射 Constructor、Method、Field 基本用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅析数据库case when 用法
- 下一篇: Java线程之Synchronized用