反射 — Java 高級開發必須懂的

2022-01-22 程式設計師大咖

作者丨rocomp

www.cnblogs.com/rocomp/p/4781987.html

理解反射對學習Java框架有很大的幫助,如Spring框架的核心就是使用Java反射實現的,而且對做一些Java底層的操作會很有幫助。 

一、Class類的使用

1、萬事萬物皆對象,(當然,基本數據類型,靜態成員不是面向對象(屬於類的)),所以我們創建的每一個類也都是對象,即類本身是java.lang.Class類的實例對象,但是這些對象都不需要new出來,因為java.lang.Class類的構造方法是私有的

2、任何一個類都是Class類的實例對象,這個實例對象有三種表示方式:(我們新建一個Student類)

Class c1 = Student.class;//實際告訴我們任何一個類都有一個隱含的靜態成員變量class(知道類名時用)

Class c2 = stu.getClass();//已知該類的對象通過getClass方法(知道對象時用)  

Class c3 = Class.forName("類的全名");//會有一個ClassNotFoundException異常

官網解釋說:c1,c2表示了Student類的類類型()class type),萬事萬物皆對象,類也是對象,是Class類的實例對象,這個對象我們成為該類的類類型(有點亂,但是慢慢捋一下還是能理解的)

這裡有一點值得注意,當我們執行System.out.println(c1==c2);語句,結果返回的是true,這是為什麼呢?原因是不管c1還是c2都代表了Student類的類類型,一個類可能是Class類的一個實例對象。

我們完全可以通過類的類類型創建該類的對象實例,即通過c1或c2創建Student的實例。

Student stu = (Student)c1.newInstance();//前提是必須要有無參的構造方法,因為該語句會去調用其無參構造方法。該語句會拋出異常。

 

二、動態加載類

編譯時加載類是靜態加載類,

new 創建對象是靜態加載類,在編譯時刻就需要加載所有可用使用到的類,如果有一個用不了,那麼整個文件都無法通過編譯

運行時加載類是動態加載類      

Class c =  Class.forName("類的全名"),不僅表示了類的類型,還表示了動態加載類,編譯不會報錯,在運行時才會加載,使用接口標準能更方便動態加載類的實現。功能性的類儘量使用動態加載,而不用靜態加載。

很多軟體比如QQ,360的在線升級,並不需要重新編譯文件,只是動態的加載新的東西

      

三、獲取方法信息

1、基本的數據類型,void關鍵字都存在類類型

Class c1 =int.class;
Class c2 =String.class;

Class c3 =double.class;
Class c4 =Double.class;
Class c5 =void.class;

2、Class類的基本API操作 


publicstaticvoid printClassMessage(Object obj){

Class c = obj.getClass();

System.out.println("累的名稱是:"+c.getName());


Method[] ms = c.getMethods();
for(int i =0; i < ms.length; i++){

Class retrunType = ms[i].getReturnType();
System.out.print(retrunType.getName()+" ");

System.out.print(ms[i].getName()+"(");

Class[] paraTypes = ms[i].getParameterTypes();
for(Class class1 : paraTypes){
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}

Class的API中還有很多其他的方法,可以得到interface、Package、Annotation等很多信息,具體使用請參考幫助手冊,本文就不在詳細講解。特別注意的一點是,如果你想得到一個類的信息,首先就要獲取該類的類類型。

四、獲取成員變量構造函數信息  


Field[] fs = c.getDeclaredFields();
for(Field field : fs){

Class fieldType = field.getType();
String typeName = fieldType.getName();

String fieldName = field.getName();
System.out.print(typeName+" "+fieldName);
}



Constructor[] cs = c.getDeclaredConstructors();
for(Constructor constructor : cs){
System.out.print(constructor.getName()+"(");

Class[] paramTypes = constructor.getParameterTypes();
for(Class class1 : paramTypes){
System.out.print(class1.getName()+",");
}
System.out.println(")");
}

五、方法反射的基本操作

如何獲取某個方法

       方法的名稱和方法的參數列表才能唯一決定某個方法

       Method m = c.getDeclaredMethod("方法名",可變參數列表(參數類型.class))

方法的反射操作

       m.invoke(對象,參數列表)

       方法如果沒有返回值,返回null,如果有返回值返回Object類型,然後再強制類型轉換為原函數的返回值類型

六、通過反射了解集合泛型的本質

ArrayList list1 =newArrayList();
ArrayList<String> list2 =newArrayList<String>();

Class c1 = list1.getClass();
Class c2 = list2.getClass();

System.out.println(c1==c2);

結果分析:因為反射的操作都是編譯之後的操作,也就是運行時的操作,c1==c2返回true,說明編譯之後集合的泛型是去泛型化的。

那麼我們就可以理解為,Java集合中的泛型,是用於防止錯誤類型元素輸入的,比如在list2中我們add一個int,add(10)就會編譯報錯,那麼這個泛型就可以只在編譯階段有效,通過了編譯階段,泛型就不存在了。可以驗證,我們繞過編譯,用反射動態的在list2中add一個int是可以成功的,只是這時因為list2中存儲了多個不同類型的數據(String型,和int型),就不能用for-each來遍歷了,會拋出類型轉換錯誤異常ClassCastException

補充資料:

七、關於Java類加載器內容的詳解

 

1、類的加載

當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化

加載:

       就是指將class文件讀入內存,並為之創建一個Class對象,任何類被使用時系統都會建立一個Class對象

連接:

        驗證:確保被加載類的正確性

        準備:負責為類的靜態成員分配內存,並設置默認初始化值

        解析:將類中的符號引用替換為直接引用

初始化:

        局部變量保存在棧區:必須手動初始化

        new 的對象保存在堆區:虛擬機會進行默認初始化,基本數據類型初始化值為0,引用類型初始化值為null

2、類加載的時機(只加載一次)

以下時機僅表示第一次的時候

創建類的實例的時候

訪問類的靜態變量的時候

調用類的靜態方法的時候

使用反射方式來強制創建某個類或接口對應的java.lang.Class對象

初始化某個類的子類的時候

直接使用java.exe命令來運行某個主類

 

3、類加載器

負責將.class文件加載到內存中,並為之生成對應的Class對象

雖然我們在開發過程中不需要關心類加載機制,但是了解這個機制我們就能更好的理解程序的運行

4、類加載器的組成

Bootstrap ClassLoader 根類加載器

      也被稱為引導類加載器,負責Java核心類的加載,比如System類,在JDK中JRE的lib目錄下rt.jar文件中的類

Extension ClassLoader 擴展類加載器

       負責JRE的擴展目錄中jar包的加載,在JDK中JRE的lib目錄下ext目錄

System ClassLoader 系統類加載器

      負責在JVM啟動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑,主要是我們開發者自己寫的類

 推薦↓↓↓ 

涵蓋:程式設計師大咖、源碼共讀、程式設計師共讀、數據結構與算法、黑客技術和網絡安全、大數據科技、編程前端、Java、Python、Web編程開發、Android、iOS開發、Linux、資料庫研發、幽默程式設計師等。

相關焦點

  • 阿里P8教你Java註解與反射
    講解反射前,我們先來談談靜態語言和動態語言。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們想要做什麼然後它滿足我們的要求,這類操作總是慢於直接執行相同的操作。5.3 Java反射相關的主要APIjava.lang.Class:代表一個類java.lang.reflect.Method:代表類的方法java.lang.reflect.Field
  • 「JAVA」萬字長篇詳述字節碼對象與反射機制完成動態編程
    Java 反射在Java的開發環境中,運行java文件需要使用:java xx.java 命令,運行java命令後,便會啟動JVM,將字節碼文件加載到JVM中,然後開始運行;當運行,反射提供一組api,通過調用api,便能獲取運行時的類信息;Java 中通過java.lang.reflect類庫來支持反射;03
  • 你必須掌握的 21 個 Java 核心技術!
    JVM作為java運行的基礎,很難相信對於JVM一點都不了解的人可以把java語言吃得很透。我在面試有超過3年Java經驗的開發者的時候, JVM幾乎就是一個必問的問題了。當然JVM不是唯一決定技術能力好壞的面試問題,但是可以佐證java開發能力的高低。
  • 開發崗位這麼多,為什麼選Java?你學Java了嗎-開課吧
    零基礎學Java主流開發語言根據最新2020年TIOBE程式語言指數排行榜,Java仍然排名前三位。軟體開發可以使用的語法是非常多,但是為什麼Java被廣泛的使用呢?其他程式語言與Java相比,Java語法相對簡單,並且是很多計算機語言的基礎。提到C++語言,很多人發現在使用過程中最容易出現的錯誤就是內存管理,而java有自動垃圾回收器,不用擔心內存。
  • java、php、python誰更容易學習呢?
    IT開發是公認的高薪行業吸引了很多人的加入,目前市場上受歡迎的程式語言很多,其中java是老牌程式語言,擁有很高的市場佔有率,php被看做是Web後端開發的主要語言,而python隨著人工智慧時代的到來而備受關注。
  • 第六篇:Java開發環境的安裝與部署
    前面對Java語言及開發工具有了基本了解。如果要開發Java程序,還需要安裝Java運行環境和開發工具,本篇和同學們探討Java開發環境的安裝與部署。通過本篇的學習,你將了解到Java運行及開發環境JDK的下載、安裝、檢測及JDK環境變量的配置。
  • JAVA 基礎:JAVA開發環境搭建
    ;%JAVA_HOME%\lib;(2)配置流程【我的電腦】->【屬性】->【環境變量】->【高級】->【編輯path信息】配置JAVA_HOME。打開Path變量,在變量值最前加入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;(方法同上)4.驗證:運行cmd,輸入java -version,顯示java版本則成功。
  • Java開發工具Eclipse下載安裝詳細教程
    學習 Java 語言程序設計必須選擇一個功能強大、使用簡單,能夠輔助程序設計的 IDE。Eclipse 是目前最流行的 Java 語言開發工具,它強大的代碼輔助功能,可以幫助開發人員自動完成語法修正、補全文字、代碼修復、API 提示等編碼工作,大量節省程序開發所需的時間。
  • 開課吧:Java軟體工程師一般要學習哪些課程?
    JAVA只是一種程式語言,由這個語言衍生出來領域很多,如果您有過使用JAVA語言開發經驗,那您肯定會關心JAVA的某一方向學習的問題,但您直接關心JAVA學習要學哪些課程,那我猜您一定是零基礎,作為零基礎的,以下建議僅供參考:
  • 用eclipse3.62開發第一個java程序
    3.用eclipse3.62開發第一個java程序:使用eclipse之前們需要先配置一下jdk。window/preference/java/installed JREs,詳細請見視頻。在eclipse3.62中:馬克- to-win:馬克 java社區:防盜版實名手機尾號: 73203。由於篇幅限制,想獲取更多內容,百度搜索"馬克java社區",本文轉載自【微信公眾號:馬克java社區】經微信公眾號授權轉載,如需轉載與原文作者聯繫。
  • Java書架來啦!入門到進階必看書籍推薦
    《瘋狂Java講義》深入介紹了Java編程的相關方面,全書內容覆蓋了Java的基本語法結構、Java的面向對象特徵、Java集合框架體系、Java泛型、異常處理、Java GUI編程、JDBC資料庫編程、Java注釋、Java的IO流體系、Java多線程編程、Java網絡通信編程和Java反射機制。
  • Java高級開發必會的50個性能優化的細節(珍藏版)
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫在JAVA程序中,性能問題的大部分原因並不在於JAVA語言,而是程序本身。養成良好的編碼習慣非常重要,能夠顯著地提升程序性能。
  • 課程設計指導——如何應用Java反射技術靈活地創建程序類對象實例
    利用JDK系統庫中的java.util.Properties類中的load方法可以加載屬性文件和利用Properties類中的getProperty方法獲得屬性文件中的指定屬性項目。(2)利用Java反射技術動態創建對象實例的基本步驟 首先要獲取一個要操作的類的對象,該對象屬於java.lang.Class類的實例;然後再通過Class類中的newInstance方法動態構造出對應的類的對象實例。
  • 可視化Java快速開發平臺,強大工作流引擎
    這款java快速開發平臺是一款支持JAVA/.NETCORE兩種類型,多種類型資料庫,是一套可視化的軟體快速開發工具。相比傳統代碼開發,能快速提高開發效率,幫助公司節省人力成本,擴展性也非常好。XJR快速開發平臺可以根據業務需求定製化開發出適用於自己企業的管理系統。快速平臺開發不要求會美工,會編程,小白也能快速開發出自己想用的業務功能。
  • 如何自學Java?避免誤區
    實際中在學習Java編程之前需要先學習一些編程基礎,新手零基礎怎麼自學java開發?自學java開發有什麼誤區?新手往往無非進行系統的學習,主要原因是自己搜集信息較為零散,學習過程中無專業的老師引導,自己會走進一些學習的誤區。
  • 私人收藏:這十大java開源庫深得人心!
    ·在java.util中,可以在Java中找到可用的所有集合和數據結構  ·程式設計師可以使用java.io來讀取文件,使用管道,流和其他。  ·java.nio實際上是java.io的替代品,代表了非阻塞I / O,它允許密集使用輸入/輸出操作。
  • 北京JAVA開發3年,拿到美團35K的offer面試心得
    前言長文乾貨提示,文章為大家完整記錄了一位在北京做了3年的JAVA開發的朋友,如何通過美團的面試及拿到35K的offer,請記得點讚收藏支持哦
  • 對衝定製軟體app開發中的Java語言
    在當前的社會中,智慧型手機已經成為人們生活和工作不可缺少的重要工具,而隨著市場需求的不斷增加,手機對衝軟體開發需求也在不斷的擴大。為了最大限度地滿足人們的日常需求,也為了搶佔爭奪的市場,對衝app軟體開發成為當前社會比較熱門的行業。
  • java開發工程師 javascript的字符串
    寫在前面:java作為一門世界級程式語言金字塔頂尖的語言。需要大量的練習、練習、練習來鞏固自己所獲得的知識。
  • JAVA工具JDK安裝配置詳解
    學習Java,在自己的電腦上安裝Java的開發工具包JDK是必須的。安裝完成後需要進行一系列的手動配置環境,下面介紹如何進行JDK的安裝與配置1.進入JDK的官方網站下載相關的JDK安裝工具包。5.使用滑鼠右鍵點擊【此電腦】-【屬性】-【高級系統設置】開啟系統屬性的界面,在【系統屬性】的界面中切換至【高級】選項卡,點擊打開下面的【環境變量】6.在這裡我們新建一個用戶變量,如下:點擊【新建】,在新建的界面中,設置輸入變量名為JAVA_HOME,變量值指向你安裝JDK的目錄,這裡為C:\program files\