最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java 類的加載、連接和初始化

 更新時間:2020年06月23日 11:20:50   作者:認真對待世界的小白  
這篇文章主要介紹了Java 類的加載、連接和初始化的的相關(guān)資料,文中示例代碼非常詳細,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

系統(tǒng)可能在第一次使用某個類時加載該類,也可能采用預(yù)加載機制來加載某個類。本節(jié)將會詳細介紹類加載、連接和初始化過程中的每個細節(jié)。

JVM 和類

當(dāng)調(diào)用 java 命令運行某個 Java 程序時,該命令將會啟動一個 Java 虛擬機進程,不管該 Java 程序有多么復(fù)雜,該程序啟動了多少個線程,它們都處于該 Java 虛擬機進程里。正如前面介紹的,同一個 JVM 的所有線程、所有變量都處于同一個進程里,它們都使用該 JVM 進程的內(nèi)存區(qū)。當(dāng)系統(tǒng)出現(xiàn)以下幾種情況時,JVM 進程將被終止。

  • 程序運行到最后正常結(jié)束。
  • 程序運行到使用 system.exit() 或 Runtime.getRuntime().exit() 代碼處結(jié)束程序。
  • 程序執(zhí)行過程中遇到未捕獲的異?;蝈e誤而結(jié)束。
  • 程序所在平臺強制結(jié)束了 JVM 進程。

從上面的介紹可以看出,當(dāng) Java 程序運行結(jié)束時,JVM 進程結(jié)束,該進程在內(nèi)存中的狀態(tài)將會丟失。下面以類的類變量來說明這個問題。下面程序先定義了一個包含類變量的類。

public class A {
  // 定義該類的類變量
  public static int a = 6;
}

上面程序中的粗體字代碼定義了一個類變量a,接下來定義一個類創(chuàng)建A類的實例,并訪問A對象的類變量a。

public class ATest1 {
  public static void main(String[] args) {
    // 創(chuàng)建A類的實例
    A a = new A();
    // 讓a實例的類變量a的值自加
    a.a++;
    System.out.println(a.a);
  }
}

下面程序也創(chuàng)建A對象,并訪問其類變量a的值。

public class ATest2 {
  public static void main(String[] args) {
    // 創(chuàng)建A類的實例
    A b = new A();
    // 輸出b實例的類變量a的值
    System.out.println(b.a);
  }
}

在 ATest1.java 程序中創(chuàng)建了A類的實例,并讓該實例的類變量a的值自加,程序輸出該實例的類變量a的值將看到7,相信讀者對這個答案沒有疑問。關(guān)鍵是運行第二個程序 ATest2 時,程序再次創(chuàng)建了A對象,并輸出A對象類變量的a的值,此時a的值是多少呢?結(jié)果依然是6,并不是7。這是因為運行 ATest1 和 ATest2 是兩次運行 JVM 進程,第一次運行 JVM 結(jié)束后,它對A類所做的修改將全部丟失——第二次運行 JVM 時將再次初始化A類。

注意:兩次運行 Java 程序處于兩個不同的 JVM 進程中,兩個 JVM 之間并不會共享數(shù)據(jù)。

類的加載

當(dāng)程序主動使用某個類時,如果該類還未被加載到內(nèi)存中,則系統(tǒng)會通過加載、連接、初始化三個步驟來對該類進行初始化。如果沒有意外,JVM 將會連續(xù)完成這三個步驟,所以有時也把這三個步驟統(tǒng)稱為類加載或類初始化。

類加載指的是將類的 class 文件讀入內(nèi)存,并為之創(chuàng)建一個 java.lang.Class 對象,也就是說,當(dāng)程序中使用任何類時,系統(tǒng)都會為之建立一個 java.lang.Class 對象。

提示:前面介紹面向?qū)ο髸r提到:類是某一類對象的抽象,類是概念層次的東西.但不知道讀者有沒有想過:類也是一種對象就像平常說概念主要用于定義、描述其他事物,但概念本身也是一種事物,那么概念本身也需要被描述———這有點像一個哲學(xué)命題,但事實就是這樣,每個類是一批具有相同特征的對象的抽象(或者說概念),而系統(tǒng)中所有的類實際上也是實例,它們都是 java.lang.Class 的實例。

類的加載由類加載器完成,類加載器通常由 JVM 提供,這些類加載器也是前面所有程序運行的基礎(chǔ),JVM 提供的這些類加載器通常被稱為系統(tǒng)類加載器。除此之外,開發(fā)者可以通過繼承 ClassLoader 基類來創(chuàng)建自己的類加載器。

通過使用不同的類加載器,可以從不同來源加載類的二進制數(shù)據(jù),通常有如下幾種來源。

  • 從本地文件系統(tǒng)加載 class 文件,這是前面絕大部分示例程序的類加載方式。
  • 從 JAR 包加載 class 文件,這種方式也是很常見的,前面介紹 JDBC 編程時用到的數(shù)據(jù)庫驅(qū)動類就放在 JAR 文件中,JVM 可以從 JAR 文件中直接加載該 class 文件。
  • 通過網(wǎng)絡(luò)加載 class 文件。
  • 把一個 Java 源文件動態(tài)編譯,并執(zhí)行加載。

類加載器通常無須等到“首次使用”該類時才加載該類,Java 虛擬機規(guī)范允許系統(tǒng)預(yù)先加載某些類。

類的連接

當(dāng)類被加載之后,系統(tǒng)為之生成一個對應(yīng)的 Class 對象,接著將會進入連接階段,連接階段負責(zé)把類的二進制數(shù)據(jù)合并到 JRE 中。類連接又可分為如下三個階段。

(1)驗證:驗證階段用于檢驗被加載的類是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致。
(2)準(zhǔn)備:類準(zhǔn)備階段則負責(zé)為類的類變量分配內(nèi)存,并設(shè)置默認初始值。
(3)解析:將類的二進制數(shù)據(jù)中的符號引用替換成直接引用。

類的初始化
在類的初始化階段,虛擬機負責(zé)對類進行初始化,主要就是對類變量進行初始化。在 Java 類中對類變量指定初始值有兩種方式:

①聲明類變量時指定初始值;

②使用靜態(tài)初始化塊為類變量指定初始值。例如下面代碼片段。

public class Test {
  // 聲明變量a時指定初始值
  static int a = 5;
  static int b = 9; // ①
  static int c;
  static {
    // 使用靜態(tài)初始化塊為變量b指定出初始值
    b = 6;
    System.out.println("----------");
  }

  public static void main(String[] args) {
    System.out.println(Test.b);
  }
}

對于上面代碼,程序為類變量a、b都顯式指定了初始值,所以這兩個類變量的值分別為5、6,但類變量c則沒有指定初始值,它將采用默認初始值0。

聲明變量時指定初始值,靜態(tài)初始化塊都將被當(dāng)成類的初始化語句,JVM 會按這些語句在程序中的排列順序依次執(zhí)行它們,例如下面的類。

public class Test {
  static {
    // 使用靜態(tài)初始化塊為變量b指定出初始值
    b = 6;
    System.out.println("----------");
  }
  // 聲明變量a時指定初始值
  static int a = 5;
  static int b = 9; // ①
  static int c;

  public static void main(String[] args) {
    System.out.println(Test.b);
  }
}

上面代碼先在靜態(tài)初始化塊中為b變量賦值,此時類變量b的值為6;接著程序向下執(zhí)行,執(zhí)行到①號代碼處,這行代碼也屬于該類的初始化語句,所以程序再次為類變量b賦值。也就是說,當(dāng) Test 類初始化結(jié)束后,該類的類變量b的值為9。

JVM 初始化一個類包含如下幾個步驟。

①假如這個類還沒有被加載和連接,則程序先加載并連接該類。
②假如該類的直接父類還沒有被初始化,則先初始化其直接父類。
③假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句。

當(dāng)執(zhí)行第2個步驟時,系統(tǒng)對直接父類的初始化步驟也遵循此步驟1、3;如果該直接父類又有直接父類,則系統(tǒng)再次重復(fù)這三個步驟來先初始化這個父類......依此類推,所以 JVM 最先初始化的總是 java.lang.Object 類。當(dāng)程序主動使用任何一個類時,系統(tǒng)會保證該類以及所有父類(包括直接父類和間接父類〕都會被初始化。

類初始化的時機

當(dāng) Java 程序首次通過下面6種方式來使用某個類或接口時,系統(tǒng)就會初始化該類或接口。

  • 創(chuàng)建類的實例。為某個類創(chuàng)建實例的方式包括:使用 new 操作符來創(chuàng)建實例,通過反射來創(chuàng)建實例,通過反序列化的方式來創(chuàng)建實例。
  • 調(diào)用某個類的類方法(靜態(tài)方法)。
  • 訪問某個類或接口的類變量,或為該類變量賦值。
  • 使用反射方式來強制創(chuàng)建某個類或接口對應(yīng)的 java.lang.Class 對象。例如代碼:Class.forName("Person"),如果系統(tǒng)還未初始化 Person 類,則這行代碼將會導(dǎo)致該 Person 類被初始化,并返回 Person 類對應(yīng)的 java.lang.Class 對象。
  • 初始化某個類的子類。當(dāng)初始化某個類的子類時,該子類的所有父類都會被初始化。
  • 直接使用 java.exe 命令來運行某個主類。當(dāng)運行某個主類時,程序會先初始化該主類。

除此之外,下面的幾種情形需要特別指出。

對于一個 final 型的類變量,如果該類變量的值在編譯時就可以確定下來,那么這個類變量相當(dāng)于“宏變量”。Java 編譯器會在編譯時直接把這個類變量出現(xiàn)的地方替換成它的值,因此即使程序使用該靜態(tài)類變量,也不會導(dǎo)致該類的初始化。例如下面示例程序的結(jié)果。

class MyTest {
  static {
    System.out.println("靜態(tài)初始化塊...");
  }
  // 使用一個字符串直接量為static final的類變量賦值
  static final String compileConstant = "瘋狂Java講義";
}

public class CompileConstantTest {
  public static void main(String[] args) {
    // 訪問、輸出MyTest中的compileConstant類變量
    System.out.println(MyTest.compileConstant); // ①
  }
}

上面程序的 MyTest 類中有一個 compileConstant 的類變量,該類變量使用了 final 修飾,而且它的值可以在編譯時確定下來,因此 compileConstant 會被當(dāng)成“宏變量”處理。程序中所有使用 compileConstant 的地方都會在編譯時被直接替換成它的值——也就是說,上面程序中①處的粗體字代碼在編譯時就會被替換成“瘋狂Java講義”,所以①行代碼不會導(dǎo)致初始化 MyTest 類。

提示:當(dāng)某個類變量(也叫靜態(tài)變量)使用了 final 修飾,而且它的值可以在編譯時就確定下來,那么程序其他地方使用該類變量時,實際上并沒有使用該類變量,而是相當(dāng)于使用常量。

反之,如果 final 修飾的類變量的值不能在編譯時確定下來.則必須等到運行時才可以確定該類變量的值,如果通過該類來訪問它的類變量,則會導(dǎo)致該類被初始化。例如將上面程序中定義compileConstant 的代碼改為如下:

//采用系統(tǒng)當(dāng)前時間為 static final 類變量賦值
static final String compileConstant = System.currentTimeMiIlis() + "";

因為上面定義的 compileConstant 類變量的值必須在運行時才可以確定,所以①處的粗體字代碼必須保留為對 MyTest 類的類變量的引用,這行代碼就變成了使用 MyTest 的類變量,這將導(dǎo)致 MyTest 類被初始化。

當(dāng)使用 ClassLoader 類的 loadClass() 方法來加載某個類時,該方法只是加載該類,并不會執(zhí)行該類的初始化。使用 Class 的 forName() 靜態(tài)方法才會導(dǎo)致強制初始化該類。例如如下代碼。

package com.jwen.chapter18_1;

class Tester {
  static {
    System.out.println("Tester類的靜態(tài)初始化塊...");
  }
}

public class ClassLoaderTest {
  public static void main(String[] args) throws ClassNotFoundException {
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    // 下面語句僅僅是加載Tester類
    cl.loadClass("com.jwen.chapter18_1.Tester");
    System.out.println("系統(tǒng)加載Tester類");
    // 下面語句才會初始化Tester類
    Class.forName("com.jwen.chapter18_1.Tester");
  }
}

上面程序中的兩行粗體字代碼都用到了 Tester 類,但第一行粗體字代碼只是加載 Tester 類,并不會初始化 Tester 類。運行上面程序,會看到如下運行結(jié)果:

系統(tǒng)加載Tester類
Tester類的靜態(tài)初始化塊...

從上面運行結(jié)果可以看出,必須等到執(zhí)行 Class.forName("Tester") 時才完成對 Tester 類的初始化。

以上就是詳解Java 類的加載、連接和初始化的詳細內(nèi)容,更多關(guān)于Java 類的加載、連接和初始化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA實現(xiàn)空間索引編碼——GeoHash的示例

    JAVA實現(xiàn)空間索引編碼——GeoHash的示例

    本篇文章主要介紹了JAVA實現(xiàn)空間索引編碼——GeoHash的示例,如何從眾多的位置信息中查找到離自己最近的位置,有興趣的朋友可以了解一下
    2016-10-10
  • 詳解使用JRebel插件實現(xiàn)SpringBoot應(yīng)用代碼熱加載

    詳解使用JRebel插件實現(xiàn)SpringBoot應(yīng)用代碼熱加載

    這篇文章主要介紹了詳解使用JRebel插件實現(xiàn)SpringBoot應(yīng)用代碼熱加載,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • netty對proxy protocol代理協(xié)議的支持詳解

    netty對proxy protocol代理協(xié)議的支持詳解

    這篇文章主要為大家介紹了netty對proxy protoco代理協(xié)議的支持詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 從零開始學(xué)Java之關(guān)系運算符

    從零開始學(xué)Java之關(guān)系運算符

    今天帶大家復(fù)習(xí)Java關(guān)系運算符,文中對Java運算符相關(guān)知識作了詳細總結(jié),對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們很有幫助,需要的朋友可以參考下
    2021-08-08
  • SpringBoot項目防止反編譯的方案

    SpringBoot項目防止反編譯的方案

    最近項目要求部署到其他公司的服務(wù)器上,但是又不想將源碼泄露出去,要求對正式環(huán)境的啟動包進行安全性處理,防止客戶直接通過反編譯工具將代碼反編譯出來,所以本文給大家介紹了SpringBoot項目如何防止反編譯,需要的朋友可以參考下
    2024-01-01
  • 6種SpringBoot解決跨域請求的方法整理

    6種SpringBoot解決跨域請求的方法整理

    跨域資源共享是一種標(biāo)準(zhǔn)機制,允許服務(wù)器聲明哪些源可以訪問其資源,在SpringBoot應(yīng)用中,有多種方式可以解決跨域問題,本文主要介紹了6種常見的解決方案,大家可以根據(jù)需求自行選擇
    2025-04-04
  • Java實現(xiàn)指定目錄下的文件查找詳解

    Java實現(xiàn)指定目錄下的文件查找詳解

    這篇文章主要介紹了利用Java實現(xiàn)指定目錄下的文件查找的方法,能做到給出文件名,查找目錄及其子目錄中是否存在或者給出后綴名,查找目錄及其子目錄中相關(guān)的文件,感興趣的可以學(xué)習(xí)一下
    2022-03-03
  • Java Fluent Mybatis 項目工程化與常規(guī)操作詳解流程篇 下

    Java Fluent Mybatis 項目工程化與常規(guī)操作詳解流程篇 下

    Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強框架 fluent mybatis關(guān)于項目工程化與常規(guī)操作流程
    2021-10-10
  • javacv視頻抽幀的實現(xiàn)過程詳解(附代碼)

    javacv視頻抽幀的實現(xiàn)過程詳解(附代碼)

    這篇文章主要介紹了javacv視頻抽幀的實現(xiàn)過程詳解(附代碼),視頻抽幀可以做一些處理,比如水印,去水印等操作,然后再合成視頻,需要的朋友可以參考下
    2019-07-07
  • Idea調(diào)用WebService的關(guān)鍵步驟和注意事項

    Idea調(diào)用WebService的關(guān)鍵步驟和注意事項

    這篇文章主要介紹了如何在Idea中調(diào)用WebService,包括理解WebService的基本概念、獲取WSDL文件、閱讀和理解WSDL文件、選擇對接測試工具或方式、發(fā)送請求和接收響應(yīng)、處理響應(yīng)結(jié)果以及錯誤處理,需要的朋友可以參考下
    2025-01-01

最新評論

边坝县| 长岛县| 广东省| 南投市| 兴义市| 祁连县| 江山市| 尤溪县| 大宁县| 安平县| 南雄市| 蓝山县| 弋阳县| 海淀区| 潜江市| 星座| 平远县| 东莞市| 兴宁市| 沁水县| 颍上县| 扬州市| 湟源县| 日喀则市| 惠安县| 嘉禾县| 平谷区| 揭阳市| 承德市| 顺昌县| 琼海市| 新河县| 蛟河市| 姜堰市| 花垣县| 松江区| 邯郸市| 佛坪县| 宜春市| 梁河县| 遂宁市|