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

深入Java虛擬機JVM類加載初始化學習筆記

開發 后端
本篇文章主要介紹Java虛擬機JVM類加載初始化,希望對大家有所幫助。

1. Classloader的作用,概括來說就是將編譯后的class裝載、加載到機器內存中,為了以后的程序的執行提供前提條件。

2. 一段程序引發的思考:

風中葉老師在他的視頻中給了我們一段程序,號稱是世界上所有的Java程序員都會犯的錯誤。

詭異代碼如下:

Java代碼

 

  1. package test01;     
  2.     
  3. class Singleton {     
  4.     
  5.     public static Singleton singleton = new Singleton();     
  6.     public static int a;     
  7.     public static int b = 0;     
  8.     
  9.     private Singleton() {     
  10.         super();     
  11.         a++;     
  12.         b++;     
  13.     }     
  14.     
  15.     public static Singleton GetInstence() {     
  16.         return singleton;     
  17.     }     
  18.     
  19. }     
  20.     
  21. public class MyTest {     
  22.     
  23.     /**    
  24.      * @param args    
  25.      */    
  26.     public static void main(String[] args) {     
  27.         Singleton mysingleton = Singleton.GetInstence();     
  28.         System.out.println(mysingleton.a);     
  29.         System.out.println(mysingleton.b);     
  30.     }     
  31.     
  32. }    

 

一般不假思索的結論就是,a=1,b=1。給出的原因是:a、b都是靜態變量,在構造函數調用的時候已經對a和b都加1了。答案就都是1。但是運行完后答案卻是a=1,b=0。

下面我們將代碼稍微變一下

Java代碼

 

  1. public static Singleton singleton = new Singleton();     
  2. public static int a;     
  3. public static int b = 0;    

 

的代碼部分替換成

Java代碼

 

  1. public static int a;     
  2. public static int b = 0;     
  3. public static Singleton singleton = new Singleton();    

 

效果就是剛才預期的a=1,b=1。

為什么呢,這3句無非就是靜態變量的聲明、初始化,值的變化和聲明的順序還有關系嗎?Java不是面向對象的嗎?怎么和結構化的語言似地,順序還有關系。這個就是和Java虛擬機JVM加載類的原理有著直接的關系。

1. 類在JVM中的工作原理

要想使用一個Java類為自己工作,必須經過以下幾個過程

1):類加載load:從字節碼二進制文件——.class文件將類加載到內存,從而達到類的從硬盤上到內存上的一個遷移,所有的程序必須加載到內存才能工作。將內存中的class放到運行時數據區的方法區內,之后在堆區建立一個java.lang.Class對象,用來封裝方法區的數據結構。這個時候就體現出了萬事萬物皆對象了,干什么事情都得有個對象。就是到了***層究竟是雞生蛋,還是蛋生雞呢?類加載的最終產物就是堆中的一個java.lang.Class對象。

2):連接:連接又分為以下小步驟

驗證:出于安全性的考慮,驗證內存中的字節碼是否符合JVM的規范,類的結構規范、語義檢查、字節碼操作是否合法、這個是為了防止用戶自己建立一個非法的XX.class文件就進行工作了,或者是JVM版本沖突的問題,比如在JDK6下面編譯通過的class(其中包含注解特性的類),是不能在JDK1.4的JVM下運行的。

準備:將類的靜態變量進行分配內存空間、初始化默認值。(對象還沒生成呢,所以這個時候沒有實例變量什么事情)

解析:把類的符號引用轉為直接引用(保留)

3):類的初始化: 將類的靜態變量賦予正確的初始值,這個初始值是開發者自己定義時賦予的初始值,而不是默認值。

2. 類的主動使用與被動使用

以下是視為主動使用一個類,其他情況均視為被動使用!

1):初學者最為常用的new一個類的實例對象(聲明不叫主動使用)

2):對類的靜態變量進行讀取、賦值操作的。

3):直接調用類的靜態方法。

4):反射調用一個類的方法。

5):初始化一個類的子類的時候,父類也相當于被程序主動調用了(如果調用子類的靜態變量是從父類繼承過來并沒有復寫的,那么也就相當于只用到了父類的東東,和子類無關,所以這個時候子類不需要進行類初始化)。

6):直接運行一個main函數入口的類。

所有的JVM實現(不同的廠商有不同的實現,有人就說IBM的實現比Sun的要好……)在***主動調用類和接口的時候才會初始化他們。

 

 

 

 

1. 類的加載方式

1):本地編譯好的class中直接加載

2):網絡加載:java.net.URLClassLoader可以加載url指定的類

3):從jar、zip等等壓縮文件加載類,自動解析jar文件找到class文件去加載util類

4):從java源代碼文件動態編譯成為class文件

2. 類加載器

JVM自帶的默認加載器

1):根類加載器:bootstrap,由C++編寫,所有Java程序無法獲得。

2):擴展類加載器:由Java編寫。

3):系統類、應用類加載器:由Java編寫。

用戶自定義的類加載器:java.lang.ClassLoader的子類,用戶可以定制類的加載方式。每一個類都包含了加載他的ClassLoader的一個引用——getClass().getClassLoader()。如果返回的是null,證明加載他的ClassLoader是根加載器bootstrap。

如下代碼

 

 

這里面的指針就是C++的指針

1. 回顧那個詭異的代碼

從入口開始看

Singleton mysingleton = Singleton.GetInstence();

是根據內部類的靜態方法要一個Singleton實例。

這個時候就屬于主動調用Singleton類了。

之后內存開始加載Singleton類

1):對Singleton的所有的靜態變量分配空間,賦默認的值,所以在這個時候,singleton=null、a=0、b=0。注意b的0是默認值,并不是咱們手工為其賦予的的那個0值。

2):之后對靜態變量賦值,這個時候的賦值就是我們在程序里手工初始化的那個值了。此時singleton = new Singleton();調用了構造方法。構造方法里面a=1、b=1。之后接著順序往下執行。

3):

 

  1. public static int a;  
  2.  
  3.     public static int b = 0;  

 

a沒有賦值,保持原狀a=1。b被賦值了,b原先的1值被覆蓋了,b=0。所以結果就是這么來的。類中的靜態塊static塊也是順序地從上到下執行的。

2. 編譯時常量、非編譯時常量的靜態變量

如下代碼

Java代碼

  1. package test01;     
  2.     
  3. class FinalStatic {     
  4.     
  5.     public static final int A = 4 + 4;     
  6.     
  7.     static {     
  8.         System.out.println("如果執行了,證明類初始化了……");     
  9.     }     
  10.     
  11. }     
  12.     
  13. public class MyTest03 {     
  14.     
  15.     /**    
  16.      * @param args    
  17.      */    
  18.     public static void main(String[] args) {     
  19.         System.out.println(FinalStatic.A);     
  20.     }     
  21.     
  22. }    

 

結果是只打印出了8,證明類并沒有初始化。反編譯源碼發現class里面的內容是

public static final int A = 8;

也就是說編譯器很智能的、在編譯的時候自己就能算出4+4是8,是一個固定的數字。沒有什么未知的因素在里面。

將代碼稍微改一下

public static final int A = 4 + new Random().nextInt(10);

這個時候靜態塊就執行了,證明類初始化了。在靜態final變量在編譯時不定的情況下。如果客戶程序這個時候訪問了該類的靜態變量,那就會對類進行初始化,所以盡量靜態final變量盡量沒什么可變因素在里面1,否則性能會有所下降。

1. ClassLoader的剖析

ClassLoader的loadClass方法加載一個類不屬于主動調用,不會導致類的初始化。如下代碼塊

Java代碼

 

  1. ClassLoader classLoader = ClassLoader.getSystemClassLoader();     
  2. Class clazz = classLoader.loadClass("test01.ClassDemo");   

 

并不會讓類加載器初始化test01.ClassDemo,因為這不屬于主動調用此類。

ClassLoader的關系:

根加載器——》擴展類加載器——》應用類加載器——》用戶自定義類加載器

加載類的過程是首先從根加載器開始加載、根加載器加載不了的,由擴展類加載器加載,再加載不了的有應用加載器加載,應用加載器如果還加載不了就由自定義的加載器(一定繼承自java.lang. ClassLoader)加載、如果自定義的加載器還加載不了。而且下面已經沒有再特殊的類加載器了,就會拋出ClassNotFoundException,表面上異常是類找不到,實際上是class加載失敗,更不能創建該類的Class對象。

若一個類能在某一層類加載器成功加載,那么這一層的加載器稱為定義類加載器。那么在這層類生成的Class引用返回下一層加載器叫做初始類加載器。因為加載成功后返回一個Class引用給它的服務對象——也就是調用它的類加載器。考慮到安全,父委托加載機制。

 

 

ClassLoader加載類的原代碼如下

Java代碼

  1. protected synchronized Class loadClass(String name, boolean resolve)     
  2.     throws ClassNotFoundException     
  3.     {     
  4.     // First, check if the class has already been loaded     
  5.     Class c = findLoadedClass(name);     
  6.     if (c == null) {     
  7.         try {     
  8.         if (parent != null) {     
  9.             c = parent.loadClass(name, false);     
  10.         } else {     
  11.             c = findBootstrapClassOrNull(name);     
  12.         }     
  13.         } catch (ClassNotFoundException e) {     
  14.                 // ClassNotFoundException thrown if class not found     
  15.                 // from the non-null parent class loader     
  16.             }     
  17.             if (c == null) {     
  18.             // If still not found, then invoke findClass in order     
  19.             // to find the class.     
  20.             c = findClass(name);     
  21.         }     
  22.     }     
  23.     if (resolve) {     
  24.         resolveClass(c);     
  25.     }     
  26.     return c;     
  27.     }    

 

初始化系統ClassLoader代碼如下

Java代碼

 

  1. private static synchronized void initSystemClassLoader() {     
  2.     if (!sclSet) {     
  3.         if (scl != null)     
  4.         throw new IllegalStateException("recursive invocation");     
  5.             sun.misc.Launcher l = sun.misc.Launcher.getLauncher();     
  6.         if (l != null) {     
  7.         Throwable oops = null;     
  8.         scl = l.getClassLoader();     
  9.             try {     
  10.             PrivilegedExceptionAction a;     
  11.             a = new SystemClassLoaderAction(scl);     
  12.                     scl = (ClassLoader) AccessController.doPrivileged(a);     
  13.             } catch (PrivilegedActionException pae) {     
  14.             oops = pae.getCause();     
  15.                 if (oops instanceof InvocationTargetException) {     
  16.                 oops = oops.getCause();     
  17.             }     
  18.             }     
  19.         if (oops != null) {     
  20.             if (oops instanceof Error) {     
  21.             throw (Error) oops;     
  22.             } else {     
  23.                 // wrap the exception     
  24.                 throw new Error(oops);     
  25.             }     
  26.         }     
  27.         }     
  28.         sclSet = true;     
  29.     }     
  30.     }   

 

它里面調用了很多native的方法,也就是通過JNI調用底層C++的代碼。

當一個類被加載、連接、初始化后,它的生命周期就開始了,當代表該類的Class對象不再被引用、即已經不可觸及的時候,Class對象的生命周期結束。那么該類的方法區內的數據也會被卸載,從而結束該類的生命周期。一個類的生命周期取決于它Class對象的生命周期。由Java虛擬機自帶的默認加載器(根加載器、擴展加載器、系統加載器)所加載的類在JVM生命周期中始終不被卸載。所以這些類的Class對象(我稱其為實例的模板對象)始終能被觸及!而由用戶自定義的類加載器所加載的類會被卸載掉!

【編輯推薦】

  1. 詳解JVM的內存管理機制
  2. 深入Java核心:JVM中的棧和局部變量
  3. 專家答疑 Tomcat的JVM內存大小如何設置?
  4. 你不知道的5個JVM命令行標志
責任編輯:金賀 來源: JavaEye博客
相關推薦

2012-01-18 11:24:18

Java

2024-03-08 08:26:25

類的加載Class文件Java

2012-11-14 09:57:46

JavaJava虛擬機JVM

2019-03-05 14:59:42

Java虛擬機加載類

2010-03-15 14:24:59

StackHeapJVM

2010-09-17 15:12:57

JVMJava虛擬機

2024-03-12 07:44:53

JVM雙親委托機制類加載器

2012-03-01 10:51:37

JavaJVM

2010-09-25 15:59:54

JVM虛擬機

2020-05-08 16:55:48

Java虛擬機JVM

2011-06-22 13:35:55

JVM

2010-09-25 15:13:40

JVMJava虛擬機

2009-08-14 17:52:27

C#對象初始化

2011-12-28 13:38:00

JavaJVM

2011-12-28 13:24:47

JavaJVM

2020-05-12 22:24:44

JVM系統加載器

2024-09-04 09:47:21

2024-03-29 11:42:21

Java虛擬機

2019-07-24 16:04:47

Java虛擬機并發

2021-02-28 11:58:33

JVM機制語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕亚洲一区二区三区 | 国产精品毛片无码 | 国产一区二区三区在线看 | 国产一区久久久 | 国产一区不卡 | 成人在线电影在线观看 | 欧美日本在线观看 | 操操操av | 天堂一区在线观看 | 亚洲欧美日韩国产 | 日韩在线精品视频 | 最新中文字幕第一页视频 | 在线观看欧美日韩视频 | 日韩在线小视频 | 色婷婷亚洲一区二区三区 | 久久久区 | 日本一卡精品视频免费 | 欧美黄色网络 | 中文字幕在线视频免费视频 | 免费同性女女aaa免费网站 | 久热免费 | 天堂在线一区 | 亚洲国产一区二区在线 | 国产熟熟 | 韩日精品一区 | 日本三级电影免费观看 | 91成人小视频 | 视频在线一区二区 | 久久久久国产精品午夜一区 | 噜噜噜噜狠狠狠7777视频 | 99久久日韩精品免费热麻豆美女 | 91精品久久久久久久久久 | 在线观看中文视频 | 亚州综合一区 | 国产精品久久久亚洲 | 亚洲人成在线播放 | 国产精品国产三级国产aⅴ无密码 | 国产高清久久久 | 欧美精品一区二区三区在线 | 精品无码久久久久久国产 | 免费在线成人网 |