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