JAVA反射机制及其原理实现
?
9.1 概念
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;public、protected、private。
OO(面向對象),private私有的,不能訪問。這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。**
反射就是把java類中的各種成分映射成一個個的Java對象 例如:一個類有:成員變量、方法、構造方法、包等等信息,利用反射技術可以對一個類進行解剖,把各個組成部分映射成一個個對象。
物理:有個反射的概念,通過鏡子,可以知道物體的存在。看到一個鏡像或名字等,知道物體在哪里。
(其實:一個類中這些成員方法、構造方法、在加入類中都有一個類來描述) 如圖是類的正常加載過程:反射的原理在與class對象。 熟悉一下加載的時候:Class對象的由來是將class文件讀入內存,并為之創建一個Class對象。
Student.java--->Student.class 經過編譯成了一個字節碼文件。
?
9.2 作用
在日常的第三方應用開發過程中,經常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統應用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法。當然,也不是所有的都適合反射,之前就遇到一個案例,通過反射得到的結果與預期不符。閱讀源碼發現,經過層層調用后在最終返回結果的地方對應用的權限進行了校驗,對于沒有權限的應用返回值是沒有意義的缺省值,否則返回實際值起到保護用戶的隱私目的。
反射是框架設計的靈魂
(使用的前提條件:必須先得到代表的字節碼的Class,Class類用于表示.class文件(字節碼))
9.2.1 反編譯:.class-->.java
9.2.2通過反射機制訪問java對象的屬性,方法,構造方法等;
User user=new User();--》形成的java文件-->XXX.class
將來賦值的時候,不是User類,是不是就報錯了啊。存在緊耦合的狀態,我們做OO的目的就是高內聚、松耦合,說白了,就是模塊內部實現特定功能,模塊與模塊之間,關聯度不大。
這種方式,是編譯時
我們以后寫程序,更多的應該是運行時給值。
?
9.3 反射機制的相關類
與Java反射相關的類如下:
| Class類 | 代表類的實體,在運行的Java應用程序中表示類和接口 |
| Field類 | 代表類的成員變量(成員變量也稱為類的屬性) |
| Method類 | 代表類的方法 |
| Constructor類 | 代表類的構造方法 |
9.3.1 查看Class類在java中的api
Class 類的實例表示正在運行的 Java 應用程序中的類和接口。也就是jvm中有N多的實例每個類都有該Class對象。(包括基本數據類型) Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了。
沒有公共的構造方法,方法共有64個太多了。下面用到哪個就詳解哪個吧
9.3.2 根據一個字符串得到一個類
| String | getClass | 表示此對象運行時類的 Class 對象 |
| Class | forName | 具有指定名的類的 Class 對象 |
| 包裝類 | 無 | 屬性Type |
參考代碼:
? String str="今天是反射課程";Class clz=str.getClass();//得到當前正在運行的類;System.out.println(clz);Class clz2=Integer.TYPE; //包裝類型,不同;包裝類.TypeSystem.out.println(clz2);System.out.println(Boolean.TYPE);System.out.println(Double.TYPE);System.out.println(Character.TYPE);?9.3.3 獲取Class對象的 三種方式
-
Object:getClass
-
任何數據類型(包含基本數據類型)都有一個"靜態"的class屬性,這時候可以通過類名.屬性訪問.
-
通過Class類的靜態方法:forName(string className路徑)
參考代碼
//1.使用第一種方式來獲取User的Class對象;User user=new User(); //弄了一個User對象,在內存里面;Class clz1=user.getClass(); //對象.getClassSystem.out.println(clz1); //clz1:是什么類呢?com.aaa.chapter07.User;路徑+類名;//2.使用第二種方式;Class clz2=User.class; //類名.class 這個靜態屬性.System.out.println(clz2);//這時候,我們是不是考慮一下,之前講的那個原理圖。證明原理圖,里面,正在運行的Class是一個。System.out.println(clz1==clz2);//3.Class.forName(類路徑方式)try {Class clz3=Class.forName("com.aaa.chapter07.User");System.out.println(clz3);System.out.println(clz2==clz3);} catch (ClassNotFoundException e) {e.printStackTrace();}提問?最常用哪種?一般用第三個。松耦合方式。
9.3.4 通過反射來獲取構造方法
調用方法:
1.獲取構造方法:
1).批量的方法: public Constructor[] getConstructors():所有"公有的"構造方法 public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)
2).獲取單個的方法,并調用: public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法: public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、默認、公有;
例如:
調用構造方法: Constructor-->newInstance(Object... initargs)
package com.aaa.chapter07;import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.sql.Connection;/*** Created by 張晨光 on 2020/3/10 10:24*/ public class Constructors {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class clz=Class.forName("com.aaa.chapter07.User");//2.獲取所有公共字段; // Field[] fields = clz.getFields(); // for(Field f:fields){ // System.out.println(f); // }//2.獲取所有共有 私有字段; // Field[] fields = clz.getDeclaredFields(); // for(Field f:fields){ // System.out.println(f); // }Field field=clz.getField("country");System.out.println(field);Object obj=clz.getConstructor().newInstance();field.set(obj,"中國");User u=(User)obj;System.out.println(u.getCountry());} }2、newInstance是 Constructor類的方法(管理構造函數的類) api的解釋為: newInstance(Object... initargs) 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,并用指定的初始化參數初始化該實例。 它的返回值是T類型,所以newInstance是創建了一個構造方法的聲明類的新實例對象。并為之調用
?
package com.aaa.chapter07;import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;/*** Created by 張晨光 on 2020/3/10 22:29*/ public class InstanceDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class clz=Class.forName("com.aaa.chapter07.User");//1.調用第一個默認構造方法,沒有參數,創建實例之后,再次使用setter賦值。 // Constructor constructor = clz.getConstructor();//Alt+Enter, // Object obj=constructor.newInstance(); // User user=(User)obj; // user.setName("張老師"); // System.out.println(obj);//2.調用第二個有3個參數的構造方法,公共的構造方法,注意里面參數的使用方式. // Constructor constructor2 = clz.getConstructor(String.class,char.class,Integer.class); // Object obj2=constructor2.newInstance("張晨光",'男',18);//類似于之前的構造方法,填充值; // User user2=(User)obj2; // System.out.println(user2);//3.調用第三個私有構造方法,這個構造方法,我們說外部無法訪問.Constructor declaredConstructor = clz.getDeclaredConstructor(String.class);//設置私有構造方法,可以訪問,強制(暴力)訪問.declaredConstructor.setAccessible(true);Object obj=declaredConstructor.newInstance("登徒子");User user3=(User)obj;System.out.println(user3);} }9.3.5 獲取成員變量并調用
獲取成員變量并調用:
1.批量的
1).Field[] getFields():獲取所有的"公有字段"
2).Field[] getDeclaredFields():獲取所有字段,包括:私有、受保護、默認、公有;
2.獲取單個的:
1).public Field getField(String fieldName):獲取某個"公有的"字段;
2).public Field getDeclaredField(String fieldName):獲取某個字段(可以是私有的)
設置字段的值:
Field --> public void set(Object obj,Object value):
參數說明:
1.obj:要設置的字段所在的對象;
2.value:要為字段設置的值;
總結
以上是生活随笔為你收集整理的JAVA反射机制及其原理实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IntelliJ IDEA如何设置添加类
- 下一篇: IDEA使用指南常用快捷键