搜尋
首頁Javajava教程Java動態類別載入和重新載入的詳細介紹

這篇文章帶給大家的內容是關於Java動態類別載入和重新載入的詳細介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Java中可以在運行時載入和重新載入類,雖然並不像我們想像中那麼簡單。本文將解釋何時、怎樣在Java中載入、重新載入類別。
你可以爭論動態載入類別是Java反射的一部分還是Java核心的一部分。不管怎樣,我把它放在了Java反射中,因為沒有更好的地方放置它。

類別的載入器

Java程式的所有類別都是使用 java.lang.ClassLoader的一些子類別載入的。因此,動態載入類別也必須使用 java.lang.ClassLoader的子類別。
當一個類別載入,它所引用的類別也會被載入。類別載入模式是遞歸載入的,直到所有需要的類別載入完畢。這可能並不是應用程式的所有類別。未被引用的類別在引用前不會被載入。

類別載入層級結構

類別載入在Java中被組織成層級。當你建立一個獨立的ClassLoader,你必須提供一個父級ClassLoader。如果ClassLoader被要求載入一個類,它會請求它的父級ClassLoader去載入它。如果父級類別載入器找不到這個類,子類別載入器會嘗試自載入。

類別載入

類別載入器載入類別的步驟如下:

  1. #檢查該類別是否已載入

  2. #如類別未加載,請求父類別載入器載入它

  3. 如父類別載入器不能載入該類,嘗試使用目前類別載入器載入它

當你實作一個能夠重載類別的類別載入器時,你需要從這個序列中偏離一點。不應請求父類別載入程式載入要重裝的類別。稍後再談。

動態類別載入

動態載入類別非常簡單。你需要做的一切是取得一個ClassLoader並呼叫它的loadClass()方法。範例如下:

public class MainClass {

  public static void main(String[] args){

    ClassLoader classLoader = MainClass.class.getClassLoader();

    try {
        Class aClass = classLoader.loadClass("com.jenkov.MyClass");
        System.out.println("aClass.getName() = " + aClass.getName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

動態類別重新載入

動態類別重新載入有一些挑戰。 Java內建的類別載入器在載入類別之前總是會檢查類別是否已載入。因此,使用Java的內建類別載入器不可能重新載入類別。重新載入一個類別你必須實作自己的ClassLoader子類別。
即使使用類別載入器的自訂子類,也會遇到挑戰。所有已載入的類別都需要被連結。這個方法是final的,因此不能被你的ClassLoader子類別重載。 resolve()方法不允許ClassLoader實例連結一個類別2次。因此,每當你需要重新載入類別時,你必須重新建立一個ClassLoader類別的實例。這不是不可能的,但必須知道何時設計類別重新載入。

類別重載程式設計

如上文述,不能使用載入指定類別的ClassLoader重新載入這個類別。因此,必須使用不同的ClassLoader來載入這個類別。但是,這會帶來新的問題。
Java程式中載入的每一個類別都以其全限定名(包名 類別名稱)標識,並且由ClassLoader實例載入。這意味著,類別MyObject由類別載入器A載入,是和由類別載入器B載入的相同類別MyObject不相同。模擬程式碼如下:

MyObject object = (MyObject)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

注意,類別MyObject在程式碼中是如何被引用的,是作為object類型的變數。這導致MyObject類別被已載入過這個類別的駐留程式碼的類別載入器載入。
如果myClassReloadingFactory物件工廠使用與駐留程式碼不同的類別載入器來載入MyObject,你不能強制轉換重新載入的Object類型的變數MyObject為MyObject類型。因為這兩個MyObject由不同的類別載入器加載,他們被視為不同的類,儘管他們擁有相同的全限定名稱。嘗試強轉一個object的類別為另一個類別的參考將拋出ClassCastException。
有可能繞過這個限制,但是你必須用兩種方式來改變你的程式碼:

  1. 使用介面作為變數類型,並且只重新載入實作類別

  2. 使用超類別作為變數類型,並且只重新載入子類別

#這裡是範例程式碼:

MyObjectInterface object = (MyObjectInterface)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");
MyObjectSuperclass object = (MyObjectSuperclass)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

如果變數類型是介面或超類,上面的程式碼都會正常運行,介面或超類在重新載入實作或子類時不會被重新載入。
為了上面程式碼的正常運行,你當然需要實作自己的類別載入器,讓介面或超類別由其父類別載入。當你的類別載入器被要求載入MyObject時,它也會被要求載入MyObjectInterface介面或MyObjectSuperclass類,因為它們被MyObject類別在內部引用。你的類別載入器必須把類別載入委派給相同的類別載入器,也就是載入了介面或超類別的類別載入器。

类加载器加载/重新加载示例

上文包含了很多内容。让我们看一下简单的示例。下面是一个简单的ClassLoader子类。注意它如何将类加载委托给它的父类,除了它想要重装的一个类之外。如果类加载被委派给了它的父类,它以后将不能被重新加载。记住,一个类只能被同一个ClassLoader实例加载。
如前所述,这只是一个示例,它显示了类加载器的行为的基本知识。这并不是一个你的类加载器的生产就绪的模板。你的类加载器可能并不仅限于一个类,可能是一个你想要重新加载的类的集合。此外,你也不能硬编码class path。

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        if(!"reflection.MyObject".equals(name))
                return super.loadClass(name);

        try {
            String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
                            "classes/reflection/MyObject.class";
            URL myUrl = new URL(url);
            URLConnection connection = myUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();

            return defineClass("reflection.MyObject",
                    classData, 0, classData.length);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

下面是使用MyClassLoader的示例:

public static void main(String[] args) throws
    ClassNotFoundException,
    IllegalAccessException,
    InstantiationException {

    ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class myObjectClass = classLoader.loadClass("reflection.MyObject");

    AnInterface2       object1 =
            (AnInterface2) myObjectClass.newInstance();

    MyObjectSuperClass object2 =
            (MyObjectSuperClass) myObjectClass.newInstance();

    //create new class loader so classes can be reloaded.
    classLoader = new MyClassLoader(parentClassLoader);
    myObjectClass = classLoader.loadClass("reflection.MyObject");

    object1 = (AnInterface2)       myObjectClass.newInstance();
    object2 = (MyObjectSuperClass) myObjectClass.newInstance();

}

reflection.MyObject类是由自定义类加载器加载的。注意,它是如何继承一个超类、实现一个接口的。这只是为了这个例子。在你的代码中,只需要两个中的一个,继承超类或实现接口。

public class MyObject extends MyObjectSuperClass implements AnInterface2{
    //... body of class ... override superclass methods
    //    or implement interface methods
}

以上是Java動態類別載入和重新載入的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault思否。如有侵權,請聯絡admin@php.cn刪除
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具