面試官:直接 new 對象不行嗎,為何用反射?
new 是靜态編譯,隻能用于編譯期就能确定的類型, 而反射可以在運作時才确定類型并建立其對象。Java的反射機制就是動态編譯,增加程式的靈活性,解耦。
具體來說就是靜态編譯是在編譯的時候把你所有的子產品都編譯到程式中,當你啟動這個程式的時候所有子產品都加載進來了。當程式比較大時,加載的過程(就是當你運作程式時初始化的過程)就比較慢了。動态編譯就不一樣了,你編譯的時候那些子產品都沒有編譯進去,一般情況下你可以把那些子產品都編譯成dll,這樣你啟動程式(初始化)的時候這些子產品不會被加載,而是在運作的時候,用到那個子產品就調用哪個子產品。
比如:Spring中的 IOC(工廠模式)
https://blog.csdn.net/a745233700/article/details/82893076
分别說說 使用new建立對象 和 通過反射建立對象 的差別,優劣勢?
什麼是反射
反射就是把 Java 類中的各種成分映射成一個個的 Java 對象。
Java反射機制的本質是JVM得到class對象之後,再通過class對象進行反編譯,進而擷取對象的各種資訊。其核心是在程式運作時動态加載類并擷取類的詳細資訊,進而操作類或對象的屬性和方法。
和 new 建立對象 的差別
https://www.cnblogs.com/jiazhutao/p/12447385.html
(1)new隻有在知道類名之後才能new,而反射有時候不需要。
知道類名的情況:
Class<?> c1 = Class.forName(“cn.classes.OneClass”);
Class<?> c2 = new OneClass.getClass();
Class<?> c3 = OneClass.class();
不知道類名的情況:
首先jvm在其内部通過函數ProxyGenerator.generateProxyClass()方法來生成代理對象的位元組碼檔案(其實 就沒有具體檔案,一切都是在記憶體中,暫時就這麼叫吧),然後defineClass0()函數利用之前生成的二進制位元組碼檔案來建立類Class對象,并順便為代理類命名(proxyName是在位元組碼檔案生成之前自己命名的),經過這個過程我們就可以在不知道類名的情況下得到了類Class對象了,然後就可以使用反射來擷取對象執行個體了(這其中牽扯到類加載的加載過程
(2)new出來的對象中,我們是無法反問她的私有屬性,而反射可以(通過setAccessible()取通路)
(3)new屬于靜态編譯,而反射屬于動态編譯。靜态編譯就是在編譯的時候把你所有的子產品都編譯進exe裡去,當你啟動這個exe的時候所有子產品都加載進來了。當程式比較大時,加載的過程(就是當你運作程式時初始化的過程)就比較費力了。動态編譯就不一樣了,你編譯的時候那些子產品都沒有編譯進去,一般情況下你可以把那些子產品都編譯成dll,這樣你啟動程式(初始化)的時候這些子產品不會被加載,而是在運作的時候,用到那個子產品就調用哪個子產品。
優缺點
優點:
在運作時獲得類的各種内容,進行反編譯,對于Java這種先編譯再運作的語言,能夠讓我們很友善的建立靈活的代碼,這些代碼可以在運作時裝配,無需在元件之間進行源代碼的連結,更加容易實作面向對象。
缺點:
(1)反射會消耗一定的系統資源,且性能低。
(2)反射調用方法時可以忽略權限檢查,是以可能會破壞封裝性而導緻安全問題。
用途
(1)反編譯:.class ——> .java
(2)通過反射機制通路java對象的屬性,方法,構造方法等
(3)當我們在使用IDE,比如Ecplise,IDEA時,當我們輸入一個對象或者類,并想調用他的屬性和方法是,一按點号,編譯器就會自動列出他的屬性或者方法,這裡就是用到反射。
(4)反射最重要的用途就是開發各種通用架構。比如很多架構(Spring)都是配置化的(比如通過XML/YML檔案配置Bean),為了保證架構的通用性,他們可能需要根據配置檔案加載不同的類或者對象,調用不同的方法,這個時候就必須使用到反射了,運作時動态加載需要的加載的對象。
(4)* 加載資料庫驅動的,用到的也是反射。Class.forName(“com.mysql.jdbc.Driver”);
這些部落格确實不錯:
程式人生:學Java反射,看這篇就夠了 | 原力計劃
架構師社群:Java 反射:架構設計的靈魂
業餘草:面試官:什麼是Java反射?它的應用場景有哪些?
Java技術棧:Java反射是什麼?看這篇絕對會了!
Java技術棧:Java 反射,這篇寫的很透徹!