成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

談java中類的加載、鏈接和初始化

開發(fā) 后端
本文介紹的是java中的類的類的加載、鏈接和初始化等相關(guān)的問題,希望對你有幫助,一起來看吧!

Java字節(jié)代碼的表現(xiàn)形式是字節(jié)數(shù)組(byte[]), 而Java類在JVM中的表現(xiàn)形式是java. lang. Class類的對象。 一個Java類從字節(jié)代碼到能夠在JVM中被運用, 需要經(jīng)過加載、鏈接和初始化這三個步驟。

這三個步驟中, 對開發(fā)人員直接可見的是Java類的加載, 通過運用Java類加載器(class loader)可以在運行時辰靜態(tài)的加載一個Java類;而鏈接和初始化則是在運用Java類之前會發(fā)生的舉措。 本文會詳細引見Java類的加載、鏈接和初始化的進程。

Java類的加載

Java類的加載是由類加載器來完成的。 普通來說, 類加載器分成兩類:啟動類加載器(bootstrap)和用戶自定義的類加載器(user-defined)。 兩者的區(qū)別在于啟動類加載器是由JVM的原生代碼實現(xiàn)的, 而用戶自定義的類加載器都繼承自Java中的java. lang. ClassLoader類。 在用戶自定義類加載器的部分, 普通JVM都會提供一些根本實現(xiàn)。 應(yīng)用順序的開發(fā)人員也可以依據(jù)需要編寫自己的類加載器。 JVM中最常運用的是零碎類加載器(system), 它用來啟動Java應(yīng)用順序的加載。 通過java. lang. ClassLoader的getSystemClassLoader()方法可以獲取到該類加載器對象。 

類加載器需要完成的最終功能是定義一個Java類, 即把Java字節(jié)代碼轉(zhuǎn)換成JVM中的java. lang. Class類的對象。 但是類加載的進程并不是這么簡單。 Java類加載器有兩個比較重要的特征:層次組織構(gòu)造和代理形式。 層次組織構(gòu)造指的是每個類加載器都有一個父類加載器, 通過getParent()方法可以獲取到。 類加載器通過這種父親-后代的方式組織在一起, 構(gòu)成樹狀層次構(gòu)造。 代理形式則指的是一個類加載器既可以自己完成Java類的定義任務(wù), 也可以代理給其它的類加載器來完成。

由于代理形式的存在, 啟動一個類的加載進程的類加載器和最終定義這個類的類加載器能夠并不是一個。 前者稱為初始類加載器, 然后者稱為定義類加載器。 兩者的關(guān)聯(lián)在于:一個Java類的定義類加載器是該類所導(dǎo)入的其它Java類的初始類加載器。 比方類A通過import導(dǎo)入了類 B, 那么由類A的定義類加載器負責(zé)啟動類B的加載進程。

普通的類加載器在嘗試自己去加載某個Java類之前, 會首先代理給其父類加載器。 當(dāng)父類加載器找不到的時候, 才會嘗試自己加載。 這個邏輯是封裝在java. lang. ClassLoader類的loadClass()方法中的。 普通來說, 父類優(yōu)先的戰(zhàn)略就足夠好了。 在某些狀況下, 能夠需要采取相反的戰(zhàn)略, 即先嘗試自己加載, 找不到的時候再代理給父類加載器。

這種做法在Java的Web容器中比較常見, 也是Servlet規(guī)范推薦的做法。 比方, Apache Tomcat為每個Web應(yīng)用都提供一個獨立的類加載器, 運用的就是自己優(yōu)先加載的戰(zhàn)略。 IBM WebSphere Application Server則允許Web應(yīng)用選擇類加載器運用的戰(zhàn)略。

類加載器的一個重要用途是在JVM中為相同名稱的Java類創(chuàng)立隔離空間。 在JVM中, 判斷兩個類是否相同, 不僅是依據(jù)該類的二進制名稱, 還需要依據(jù)兩個類的定義類加載器。 只有兩者完全一樣, 才認為兩個類的是相同的。 因此, 即便是異樣的Java字節(jié)代碼, 被兩個不同的類加載器定義之后, 所失掉的Java類也是不同的。 假如試圖在兩個類的對象之間停止賦值操作, 會拋出java. lang. ClassCastException。

這個特性為異樣名稱的Java類在JVM中共存創(chuàng)造了條件。 在實際的應(yīng)用中, 能夠會要求同一名稱的Java類的不同版本在JVM中可以同時存在。 通過類加載器就可以滿足這種需求。 這種技術(shù)在OSGi中失掉了廣泛的應(yīng)用。

Java類的鏈接

Java類的鏈接指的是將Java類的二進制代碼合并到JVM的運行狀態(tài)之中的進程。 在鏈接之前, 這個類必需被成功加載。 類的鏈接包括驗證、準備和解析等幾個步驟。 驗證是用來確保Java類的二進制表示在構(gòu)造上是完全正確的。 假如驗證進程出現(xiàn)錯誤的話, 會拋出java. lang. VerifyError錯誤。 準備進程則是創(chuàng)立Java類中的靜態(tài)域, 并將這些域的值設(shè)為默許值。 準備進程并不會執(zhí)行代碼。

在一個Java類中會包含對其它類或接口的形式援用, 包括它的父類、所實現(xiàn)的接口、方法的形式參數(shù)和前往值的Java類等。 解析的進程就是確保這些被援用的類能被正確的找到。 解析的進程能夠會導(dǎo)致其它的Java類被加載。

不同的JVM實現(xiàn)能夠選擇不同的解析戰(zhàn)略。 一種做法是在鏈接的時候, 就遞歸的把所有依賴的形式援用都停止解析。 而另外的做規(guī)律能夠是只在一個形式援用真正需要的時候才停止解析。 也就是說假如一個Java類只是被援用了, 但是并沒有被真正用到, 那么這個類有能夠就不會被解析。 思索上面的代碼:

  1. public class LinkTest . . . {  
  2. public static void main(String[] args) . . . {  
  3. ToBeLinked toBeLinked = null;  
  4. System. out. println(Test link. );  
  5. }  

類 LinkTest援用了類ToBeLinked, 但是并沒有真正運用它, 只是聲明了一個變量, 并沒有創(chuàng)立該類的實例或是訪問其中的靜態(tài)域。 在 Oracle的JDK 6中, 假如把編譯好的ToBeLinked的Java字節(jié)代碼刪除之后, 再運行LinkTest, 順序不會拋出錯誤。 這是由于ToBeLinked類沒有被真正用到, 而Oracle的JDK 6所采用的鏈接戰(zhàn)略使得ToBeLinked類不會被加載, 因此也不會發(fā)現(xiàn)ToBeLinked的Java字節(jié)代碼實際上是不存在的。 假如把代碼改成ToBeLinked toBeLinked = new ToBeLinked();之后, 再按照相同的方法運行, 就會拋出異常了。 由于這個時候ToBeLinked這個類被真正運用到了, 會需要加載這個類。

Java類的初始化

當(dāng)一個Java類第一次被真正運用到的時候, JVM會停止該類的初始化操作。 初始化進程的主要操作是執(zhí)行靜態(tài)代碼塊和初始化靜態(tài)域。 在一個類被初始化之前, 它的直接父類也需要被初始化。 但是, 一個接口的初始化, 不會引起其父接口的初始化。 在初始化的時候, 會按照源代碼中從上到下的順序依次執(zhí)行靜態(tài)代碼塊和初始化靜態(tài)域。 思索上面的代碼:

  1. public class StaticTest . . . {  
  2. public static int X = 10;  
  3. public static void main(String[] args) . . . {  
  4. System. out. println(Y); //輸入60  
  5. }  
  6. static . . . {  
  7. X = 30;  
  8. }  
  9. public static int Y = X * 2;  

在上面的代碼中, 在初始化的時候, 靜態(tài)域的初始化和靜態(tài)代碼塊的執(zhí)行會從上到下依次執(zhí)行。 因此變量X的值首先初始化成10, 后來又被賦值成30;而變量Y的值則被初始化成60。

Java類和接口的初始化只有在特定的機遇才會發(fā)生, 這些機遇包括:

創(chuàng)立一個Java類的實例。 如:MyClass obj = new MyClass()

調(diào)用一個Java類中的靜態(tài)方法。 如:MyClass. sayHello()

在頂層Java類中執(zhí)行assert語句。 

通過Java反射API也能夠形成類和接口的初始化。 需要注意的是, 當(dāng)訪問一個Java類或接口中的靜態(tài)域的時候, 只有真正聲明這個域的類或接口才會被初始化。 思索上面的代碼:

  1. class B . . . {  
  2. static int value = 100;  
  3. static . . . {  
  4. System. out. println(Class B is initialized. ); //輸入  
  5. }  
  6. }  
  7. class A extends B . . . {  
  8. static . . . {  
  9. System. out. println(Class A is initialized. ); //不會輸入  
  10. }  
  11. }  
  12. public class InitTest . . . {  
  13. public static void main(String[] args) . . . {  

創(chuàng)立自己的類加載器

在 Java應(yīng)用開發(fā)進程中, 能夠會需要創(chuàng)立應(yīng)用自己的類加載器。 典型的場景包括實現(xiàn)特定的Java字節(jié)代碼查找方式、對字節(jié)代碼停止加密/解密以及實現(xiàn)同名 Java類的隔離等。 創(chuàng)立自己的類加載器并不是一件復(fù)雜的事情, 只需要繼承自java. lang. ClassLoader類并覆寫對應(yīng)的方法即可。 java. lang. ClassLoader中提供的方法有不少, 上面引見幾個創(chuàng)立類加載器時需要思索的:

  • defineClass():這個方法用來完成從Java字節(jié)代碼的字節(jié)數(shù)組到j(luò)ava. lang. Class的轉(zhuǎn)換。 這個方法是不能被覆寫的, 普通是用原生代碼來實現(xiàn)的。
  • findLoadedClass():這個方法用來依據(jù)名稱查找已經(jīng)加載過的Java類。 一個類加載器不會重復(fù)加載同一名稱的類。
  • findClass():這個方法用來依據(jù)名稱查找并加載Java類。
  • loadClass():這個方法用來依據(jù)名稱加載Java類。
  • resolveClass():這個方法用來鏈接一個Java類。

這里比較 容易混淆的是findClass()方法和loadClass()方法的作用。 前面提到過, 在Java類的鏈接進程中, 會需要對Java類停止解析, 而解析能夠會導(dǎo)致以后Java類所援用的其它Java類被加載。 在這個時候, JVM就是通過調(diào)用以后類的定義類加載器的loadClass()方法來加載其它類的。 findClass()方規(guī)律是應(yīng)用創(chuàng)立的類加載器的擴展點。 應(yīng)用自己的類加載器應(yīng)該覆寫findClass()方法來添加自定義的類加載邏輯。 loadClass()方法的默許實現(xiàn)會負責(zé)調(diào)用findClass()方法。 

前面提到, 類加載器的代理形式默許運用的是父類優(yōu)先的戰(zhàn)略。 這個戰(zhàn)略的實現(xiàn)是封裝在loadClass()方法中的。 假如希望修改此戰(zhàn)略, 就需要覆寫loadClass()方法。 

上面的代碼給出了自定義的類加載的常見實現(xiàn)形式:

  1. public class MyClassLoader extends ClassLoader . . . {  
  2. protected Class findClass(String name) throws ClassNotFoundException . . . {  
  3. byte[] b = null//查找或生成Java類的字節(jié)代碼  
  4. return defineClass(name, b, 0, b. length);  
  5. }  

希望通過以上關(guān)于java中類的加載、鏈接和初始化三方面的介紹,能夠給你帶來幫助。

責(zé)任編輯:于鐵 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2020-11-02 07:02:10

加載鏈接初始化

2024-03-08 08:26:25

類的加載Class文件Java

2024-03-12 07:44:53

JVM雙親委托機制類加載器

2012-02-28 10:04:09

Java

2012-05-23 12:46:53

JavaJava類

2012-04-09 13:43:12

Java

2019-11-04 13:50:36

Java數(shù)組編程語言

2013-03-04 11:10:03

JavaJVM

2011-06-17 15:29:44

C#對象初始化器集合初始化器

2011-06-09 14:13:06

C++JAVA缺省初始化

2022-03-30 08:19:12

JavaGroovy

2012-03-13 13:38:42

Java

2023-12-18 09:26:12

C++switchif

2022-03-21 09:50:50

JavaGroovy映射Map

2021-04-01 10:01:55

JavaStringJava基礎(chǔ)

2023-10-06 20:57:52

C++聚合成員

2022-01-04 19:33:03

Java構(gòu)造器調(diào)用

2023-11-12 23:08:17

C++初始化

2011-03-17 09:58:43

Java虛擬機JVM

2009-06-11 13:26:16

Java數(shù)組聲明創(chuàng)建
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美性一区二区三区 | 免费的日批视频 | 国产一区二区精品在线观看 | 人人人干 | 黄色片在线免费看 | 欧美一区二区三区四区五区无卡码 | 精品视频一区二区三区在线观看 | 国产精品 亚洲一区 | 干狠狠| 一区二区三区四区免费视频 | 久久综合九九 | 成人国产精品一级毛片视频毛片 | 精品国产乱码久久久久久闺蜜 | 黄色精品 | 欧美日产国产成人免费图片 | 99精品一级欧美片免费播放 | аⅴ资源新版在线天堂 | 国产中文字幕在线观看 | 精品久久伊人 | 亚洲一区免费视频 | 久久亚| 亚洲一区久久 | 毛片一级片 | 久久久免费毛片 | 国产真实精品久久二三区 | 天天操天天操 | 亚洲网在线 | av先锋资源 | 欧美日韩成人影院 | 国产一区二区三区视频 | 精品日韩一区 | 久久不卡日韩美女 | 国产免费一区二区 | 欧美成人激情 | 日日操日日干 | 在线91| 黄色一级片在线播放 | 欧美精品福利 | 亚洲高清视频在线观看 | 成人欧美一区二区 | 国产精品一区二区免费 |