你知道java反射機制中class.forName和classloader的區別嗎?

2020-12-04 愚公要移山1

前兩天頭條有朋友留言說使用class.forName找不到類,可以使用classloader加載。趁此機會總結一下,正好看到面試中還經常問到。

一、類加載機制

上面兩種加載類的方式說到底還是為了加載一個java類,因此需要先對類加載的過程進行一個簡單的了解。我們寫好的程序,然後run運行,過程可以直接看下面這張圖:

往細了看大致分為5個階段:

(1)加載:java類運行時候會生成一個class字節碼文件,加載的過程就是去我們的作業系統尋找這個class文件。

(2)連結:這個過程就是把class文件加載到java虛擬機。

(3)初始化:在虛擬機中根據class文件進行初始化。

(4)使用:這個過程大家都明白。

(5)卸載:使用完了,java虛擬機進行清理。

對於class.forName和classloader來說針對的就是第一個過程,也就是加載過程。不過這倆雖然有一定的相似性,但是區別還是挺大的。

二、使用舉例

我們使用代碼,先看看如何使用。注意包的範圍,避免加載不了。

第一步:定義User類

第二步:測試

我們在上面的test方法中,使用了兩個加載方法。現在我們測試一下:

是不感覺有點區別。現在是先給出一個大體的使用,下面我們分析一下他們的區別。

三、區別

1、class.forName

class.forName()前者除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執行類中的static塊。注意這裡的靜態塊指的是在類初始化時的一些數據。但是classloader卻沒有,想要弄清楚這個原因,還是直接到源碼中看看。

在這個源碼中我們會發現,其實底層真正實現的是forName0方法,那這幾個參數又是什麼意思呢?

(1)className:表示我們要加載的類名

(2)true:指Class被加載後是不是必須被初始化。 不初始化就是不執行static的代碼即靜態代碼,在這裡默認為true,也就是默認實現類的初始化。

(3)ClassLoader.getClassLoader(caller):表示類加載器,到這你會發現forNanme其實也是使用的ClassLoader類加載器加載的。

(4)caller:指定類加載器。

所以,在這裡你可以指定是否在class加載後被初始化。而且底層還是使用的classloader加載的。

2、classloader

在上面的案例中我們發現,classloader並沒有初始化靜態塊,原因最好還是到源碼中看。

首先我們先進入到loadclass方法中的源碼。

public Class<?> loadClass(String name)

throws ClassNotFoundException {

return loadClass(name, false);

}

這一步看起來還看不明白,沒關係這裡真正實現的是內部的loadclass,我們再跟進去看看。

這個才是真正實現的方法,在這裡的步驟其實很簡單,大致流程是先判斷class是否已經被加載,如果被加載了那就重新加載,如果沒有加載那就使用雙親委派原則加載。加載的時候並沒有指定是否要進行初始化。

所以現在他們的區別基本上很少,總結一下:

(1)class.forName()除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執行類中的static塊。當然還可以指定是否執行靜態塊。

(2)classLoader只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。

有一個小問題需要注意:我在網上看了幾篇文章,親測有錯誤,那就是class.forName其實是不會執行靜態方法的,但是會初始化靜態變量。錯誤的例子是使用了靜態方法為靜態變量賦值了。

ok,一個小知識點。如有問題,還請批評指正。

相關焦點

  • Java基礎教程:java反射機制教程
    Java反射說的是在運行狀態中,對於任何一個類,我們都能夠知道這個類有哪些方法和屬性。很多動力節點的學員在面試中都會被問到Java反射機制這個問題,為了幫助大家更好的掌握這個知識點,小編整理了一些資料分享給大家。
  • Java反射機制深入詳解
    一.概念反射就是把Java的各種成分映射成相應的Java類。Class類的構造方法是private,由JVM創建。反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。
  • Java反射初探 ——「當類也學會照鏡子」
    動態加載類 我理解的「反射」的意義(僅個人理解哈) 我理解的java反射機制就是: 提供一套完善而強大的API「反射「類的結構。打個比方,反射機制就像是一面鏡子,而類就像是一個在照著鏡子的人。鏡子(反射機制)照出(反射)了人的全貌(類的全方位的信息,例如方法,成員變量和構造器等的相關信息)為什麼要照鏡子?
  • 如何使用JAVA反射/JAVA反射實例
    JAVA反射技術,在平時我們的開發中雖然很少會用到例如讀取配製文件可能就用到這個技術,但在我們所使用的框架源碼中是經常會用到的。通過Object類中的方法實例化  c3 = X.class ; // 通過類.class實例化  System.out.println("類名稱:" + c1.getName())  ; // 得到類的名稱  System.out.println("類名稱:" + c2.getName())  ; // 得到類的名稱  System.out.println("類名稱:" + c3.getName(
  • 簡析:Java反射、Java反射定義、反射的基石
    Java反射定義在程序運行過程中,對於任意一個類,可以獲得該類的屬性和方法;對於任意一個對象,可以調用該對象的任意一個屬性和方法。在運行時動態獲取類的信息和動態調用對象的屬性和方法稱為Java反射機制。
  • Java面試高頻考點:反射機制使用大全
    作為一個Java開發工程師,在面試的過程中,反射機制也是經常會被問到的一個問題。例如Spring的IOC實現機制,其底層都是依賴於java的反射機制,因此,這是一個非常重要的知識點。對於初學java的同學來說,掌握其使用方法很有必要。
  • Java編程中基礎反射詳細解析
    類加載指的是將類的class文件讀入內存中,並為之創建一個 java.lang.Class對象,也就是說程序使用任何類的時候,都會為其創建一個class對象。反射Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;並且能改變它的屬性。
  • 學Java反射,看這篇就夠了 | 原力計劃
    反射機制是不知道類是什麼樣的,它是根據類的類名,去獲取一個實例,然後根據方法名去執行方法。好比說,一般情況下畫一隻老虎,問我得先知道老虎長什麼樣子才能畫出來;有了反射機制,我只要知道「老虎」這個名字就能畫出來。
  • 什麼是JAVA反射機制,詳細解讀JAVA面試的核心技術
    一、什麼叫Java反射機制?Java中的反射機制是指在運行狀態中,對於任意一個類,能夠動態獲取這個類中的屬性和方法;對於任意一個對象,都能夠任意調用它的屬性和方法。這種動態獲取類的信息以及動態調用對象方法的功能稱為Java的反射機制。
  • 反射——Java高級開發必須懂得
    一、Class類的使用任何一個類都是Class的實例對象,這個實例對象有三種表示方式1、任何一個類都有一個隱含的靜態成員變量classClass c1=Foo.class;2、已經知道該類的對象通過getClass
  • Java反射是什麼?看這篇絕對會了!
    反射是開源框架中的一個重要設計理念,在源碼分析中少不了它的身影,所以,今天我會儘量用淺顯易懂的語言,讓你去理解下面這幾點:(1)反射的思想以及它的作用: 概念篇(2)反射的基本使用及應用場景: 應用篇.java文件後,使用javac編譯後,就會產生一個字節碼文件.class,在字節碼文件中包含類的所有信息,如屬性,構造方法,方法······當字節碼文件被裝載進虛擬機執行時,會在內存中生成 Class 對象,它包含了該類內部的所有信息,在程序運行時可以獲取這些信息。
  • 反射原來是這麼玩的(反射一開,誰都不愛)
    反射的發展歷史1996年01月23日,jdk 1.0版本發布,代號為Oak(橡樹)。這個代號為Oak(橡樹)的版本,在發布後的第二年,1997年02月19日,發布jdk 1.1版本,這次版本發布中引入了**反射**機制。通俗的解釋就是:無論是公有還是私有的方法、屬性、構造方法,全都可以用反射進行獲取、進行賦值、調用。
  • Java 反射:框架設計的靈魂
    靜態語言:相對於動態語言來說,在編譯時變量的數據類型就已經確定(使用變量之前必須聲明數據類型),在編譯時就會進行類型是否匹配;比如 C 語言、Java ;Java 反射機制:在運行過程中,對於任意一個類,都能知道其所有的屬性和方法;對於任意一個對象,都能調用其屬性和方法;這種動態獲取類信息和調用對象方法的功能
  • 「JAVA」萬字長篇詳述字節碼對象與反射機制完成動態編程
    在Java 中有兩種方式可以得到運行時信息:一是通過RTTI,即Run-Time Type Identification,這種方式假設我們在程序編寫時就已經知道了所有對象的類型,主要是通過字節碼對象Class來獲取;二是通過「反射」機制
  • Java 反射最佳實踐
    本文的例子都可以在示例代碼中看到並下載,如果喜歡請star,如果覺得有紕漏請提交issue,如果你有更好的點子可以提交pull request。我相信有人會說:「反射就那幾個api,一直沒變過,你就不會自己去查啊,覺得麻煩就別寫代碼啊,不知道反射的內部細節你怎麼去提高呢?」其實不然,重複寫麻煩的代碼和提高自己的代碼能力是完全無關的,我實在不知道我們寫了成千上萬行的findViewById後除了知道類要和xml文件綁定外,還學到了什麼。
  • JAVA反序列化—FastJson抗爭的一生
    -1.2.46版本每個版本迭代中修改代碼,修復思路和繞過。這樣的方法名中的下劃線會被略過,得到name)。那麼以上分析結果也讓我們知道加個騷氣的小槓-應該也是可以的。至此就完成了在知道Templates觸發類原理的情況下,變形衍生到了fastjson中完成RCE。
  • Java 中的繼承和多態(深入版)
    在虛擬機中多態如何表現前文我們知道,java文件在經過javac編譯後,生成class文件之後在JVM中再進行編譯後生成對應平臺的機器碼。而JVM的編譯過程中體現多態的過程,在於選擇出正確的方法執行,這一過程稱為方法調用。
  • Java transient關鍵字使用小記
    1.transient的作用及使用方法我們都知道一個對象只要實現了Serilizable接口,這個對象就可以被序列化,java的這種序列化模式為開發者提供了很多便利,我們可以不必關係具體序列化的過程,只要這個類實現了Serilizable接口,這個類的所有屬性和方法都會自動序列化。
  • 萬字梳理,帶你拿下 Java 面試題!
    String 對象創建後會存在於運行時常量池中,運行時常量池是屬於方法區的一部分,JDK1.7 後把它移到了堆中。不可變對象不是真的不可變,可以通過反射來對其內部的屬性和值進行修改,不過一般我們不這樣做。9、static 關鍵字是幹什麼用的?談談你的理解。
  • JAVA專業術語面試100問
    2、接口和抽象類有什麼聯繫和區別?3、重載和重寫有什麼區別?4、java有哪些基本數據類型?5、數組有沒有length()方法?String有沒有length()方法?17、java中的throw 和 throws關鍵字有什麼區別?18、列舉幾個你了解的幾個常見的運行時異常?19、final, finally, finalize有什麼區別?20、描述Java內存模型?