1. 程式人生 > >反射---Java高階開發必須懂的

反射---Java高階開發必須懂的

640?wx_fmt=jpeg

理解反射對學習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();//前提是必須要有無參的構造方法,因為該語句會去呼叫其無參構造方法。該語句會丟擲異常。

二、動態載入類

1.編譯時載入類是靜態載入類

new 建立物件是靜態載入類,在編譯時刻就需要載入所有可用使用到的類,如果有一個用不了,那麼整個檔案都無法通過編譯

2.執行時載入類是動態載入類 

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

 很多軟體比如QQ,360的線上升級,並不需要重新編譯檔案,只是動態的載入新的東西

三、獲取方法資訊

1.基本的資料型別,void關鍵字都存在類型別

Class c1 =int.class;//int的類型別
Class c2 =String.class;//String類的類型別,可以理解為編譯生成的那個String.class位元組碼檔案,
//當然,這並不是官方的說法
Class c3 =double.class;
Class c4 =Double.class;
Class c5 =void.class;

2.Class類的基本API操作         

 /**
 * 列印類的資訊,包括類的成員函式,成員變數
 * @param obj 該物件所屬類的資訊
 */

publicstaticvoid printClassMessage(Object obj){
    //要獲取類的資訊,首先要獲取類的類型別
    Class c = obj.getClass();//傳遞的是哪個子類的物件,c就是該子類的類型別
    //獲取類的名稱
    System.out.println("累的名稱是:"+c.getName());

    /*
     * Method類,方法的物件
     * 一個成員方法就是一個Method物件
     * getMethods()方法獲取的是所有的public的函式,包括父類繼承而來的
     * getDeclaredMethods()獲取的是多有該類自己宣告的方法,不問訪問許可權
     */

    Method[] ms = c.getMethods();//c.getDeclaredMethods();
    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等很多資訊,具體使用請參考幫助手冊,本文就不在詳細講解。特別注意的一點是,如果你想得到一個類的資訊,首先就要獲取該類的類型別。

四、獲取成員變數建構函式資訊       

/**
 * 成員變數也是物件,是java.lang.reflect.Field這個類的的物件
 * Field類封裝了關於成員變數的操作
 * getFields()方法獲取的是所有public的成員變數的資訊
 * getDeclareFields()方法獲取的是該類自己宣告的成員變數的資訊
 */

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);
}


/**
 * 建構函式也是物件
 * java.lang.Constructor中封裝了建構函式的資訊
 * getConstructor()方法獲取所有的public的建構函式
 * getDeclaredConstructors得到所有的建構函式
 */

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(")");
}

五、方法反射的基本操作

1.如何獲取某個方法

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

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

2.方法的反射操作

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);//結果為true,為什麼??

結果分析:因為反射的操作都是編譯之後的操作,也就是執行時的操作,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包和類路徑,主要是我們開發者自己寫的類

擴充套件閱讀

來源:https://www.cnblogs.com/rocomp/p/4781987.html

文章來源網路,版權歸作者本人所有,如侵犯到原作者權益,請與我們聯絡刪除

640?wx_fmt=jpeg

相關推薦

反射---Java高階開發必須

理解反射對學習Java框架有很大的幫助,如Spring框架的核心就是使用Java反射實現的,而且

Java反射-高階開發必須

理解反射對學習Java框架有很大的幫助,如Spring框架的核心就是使用Java反射實現的,而且對做一些Java底層的操作會很有幫助。 一:Class類的使用①.萬事萬物皆物件,(當然,基本資料型別,靜態成員不是面向物件(屬於類的)),所以我們建立的每一個類也都是物件,即類本身是java.lang.Clas

慕課網_反射——Java高級開發必須

慕課網 null 決定 exce 集合泛型 ktr logs tde except 第1章 Class類的使用 1-1 Class類的使用 (15:18) 第2章 動態加載類 2-1 Java 動態加載類 (13:19) 第3章 獲取方法信息 3-1 Java 獲取方法

高階開發必須理解的Java中SPI機制

本文通過探析JDK提供的,在開源專案中比較常用的Java SPI機制,希望給大家在實際開發實踐、學習開源專案提供參考。 SPI是什麼 SPI全稱Service Provider Interface,是Java提供的一套用來被第三方實現或者擴充套件的API,它可以用來啟

想要成功應聘Java高階開發工程師,8個你必須知道的面試考綱

點選上方“程式設計師大咖”,選擇“置頂公眾號”關鍵時刻,第一時間送達!市面上,有很多Java的學

【面試總結-java高階開發工程師】第四波

一面: 1.事務的隔離級別 2.資料庫引擎 3.索引的使用 4.in 索引會失效嗎?不會 ,但是型別會是range型別 5.AOP 6.JVM 7.set可以存null嗎 hashmap的key和set

一份高質量的JAVA高階開發面試題總結

一般面試官都是按照自己的簡歷面試的,下面的面試題當然也是依據我自己的簡歷的一些問題總結,我是對一些架構知識比較感興趣,所以簡歷比較突出架構方面的。 別看人家問的問題很簡單,但是你不能簡單的回答的,依據自己的能力,能回答多深就多大多深。 然後就是看和麵試官的緣分

JAVA高階開發工程師面試系列——RocketMQ

訊息中介軟體對比 為什麼選擇RocketMQ 價效比,社群活躍度 價效比之“性”: 效能:阿里支撐,經受住淘寶,天貓雙11重重考驗;效能高;可靠性好;可用性高;易擴充套件 功能:功能完善,我們需要的功能,基本都夠滿足,如:事務訊息,訊息重試,私信佇

JAVA高階開發工程師面試系列——SpringCloud與Dubbo對比

架構完整度 Dubbo只是實現了服務治理,而Spring Cloud下面有17個子專案(可能還會新增)分別覆蓋了微服務架構下的方方面面,服務治理只是其中的一個方面,一定程度來說,Dubbo只是Spring Cloud Netflix中的一個子集。 Dub

Java Web 開發必須掌握的三個技術:Token、Cookie、Session

雞蛋 51cto tro oss 情況下 令牌 就是 數據返回 客戶端信息 在Web應用中,HTTP請求是無狀態的。即:用戶第一次發起請求,與服務器建立連接並登錄成功後,為了避免每次打開一個頁面都需要登錄一下,就出現了cookie,Session。 Cookie Cooki

面試Java高階開發崗位,只需準備這幾點,讓面試官心服口服!

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

Java高階開發必會的50個性能優化的細節

開發十年,就只剩下這套架構體系了! >>>   

高階開發不得不的Redis Cluster資料分片機制

Redis 叢集簡介 Redis Cluster 是 Redis 的分散式解決方案,在 3.0 版本正式推出,有效地解決了 Red

Java高階程式設計開發反射機制的應用

瞭解反射機制之前,我們要明確一點,java語言是面向物件程式設計的開發語言。所以,在java的世界中,萬物皆物件。 那麼這樣的話,我們在程式設計開發過程中,所建立的類是不是物件呢?是誰的物件呢?是哪個類的物件呢? 答案是肯定的。類也是物件,它是java.lang.Clas

Java 反射在實際開發中的應用

放松 hello set 加載器 glib 應該 throwable tde ffffff   運行時類型識別(RTTI, Run-Time Type Information)是Java中非常有用的機制,在java中,有兩種RTTI的方式,一種是傳統的,即假設在編譯時已

Java程序員必須知道的幾種系列輔助開發工具

java 教程 集成開發環境Eclipse是最有名也最廣泛使用的Java集成開發環境(IDE),允許開發者結合語言支持和其他功能到任何的默認包中,而且Eclipse市場有許多定制和擴展的插件。IntelliJ已經引起了開發者的“追捧”,甚至比Eclipse還受寵,有免費版和專業版。IntelliJ為眾

[轉]Java 反射在實際開發中的應用

擴展 pub 多對一 容器 redis 連接 一起 odin mapping 一:Java類加載和初始化 1.1 類加載器(類加載的工具) 1.2 Java使用一個類所需的準備工作 二:Java中RTTI   2.1 :為什麽要用到運行時類型信息

Java高階特性—反射和動態代理

1).反射   通過反射的方式可以獲取class物件中的屬性、方法、建構函式等,一下是例項: 2).動態代理   使用場景:       在之前的程式碼呼叫階段,我們用action呼叫service的方法實現業務即可。     由於之前在service中實現的業務可能不能夠滿足當先客戶的要求,需要我們重

Java開發必須掌握的 21 個 Java 核心技術!

寫這篇文章的目的是想總結一下自己這麼多年來使用java的一些心得體會,希望可以給大家一些經驗,能讓大家更好學習和使用Java。 這次介紹的主要內容是和J2SE相關的部分,另外,會在以後再介紹些J2EE相關的、和Java中各個框架相關的內容。 經過這麼多年的Java開發,以及結合平時面試Jav

java高階反射之獲取欄位(三)

package com.jk.fs; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /**  *  &nbs