亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Python > 正文

深入講解Java編程中類的生命周期

2020-01-04 17:46:47
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了深入講解Java編程中類的生命周期,在帶有垃圾回收功能的Java虛擬機上運行的程序中類的生命周期就顯得格外重要,需要的朋友可以參考下
 

引言
        最近有位細心的朋友在閱讀筆者的文章時,對java類的生命周期問題有一些疑惑,筆者打開百度搜了一下相關的問題,看到網上的資料很少有把這個問題講明白的,主要是因為目前國內java方面的教材大多只是告訴你“怎樣做”,但至于“為什么這樣做”卻不多說,所以造成大家在基礎和原理方面的知識比較匱乏,所以筆者今天就斗膽來講一下這個問題,權當拋磚引玉,希望對在這個問題上有疑惑的朋友有所幫助,文中有說的不對的地方,也希望各路高手前來指正。
        首先來了解一下jvm(java虛擬機)中的幾個比較重要的內存區域,這幾個區域在java類的生命周期中扮演著比較重要的角色:

  • 方法區:在java的虛擬機中有一塊專門用來存放已經加載的類信息、常量、靜態變量以及方法代碼的內存區域,叫做方法區。
  • 常量池:常量池是方法區的一部分,主要用來存放常量和類中的符號引用等信息。
  • 堆區:用于存放類的對象實例。
  • 棧區:也叫java虛擬機棧,是由一個一個的棧幀組成的后進先出的棧式結構,棧楨中存放方法運行時產生的局部變量、方法出口等信息。當調用一個方法時,虛擬機棧中就會創建一個棧幀存放這些數據,當方法調用完成時,棧幀消失,如果方法中調用了其他方法,則繼續在棧頂創建新的棧楨。

        除了以上四個內存區域之外,jvm中的運行時內存區域還包括本地方法棧和程序計數器,這兩個區域與java類的生命周期關系不是很大,在這里就不說了,感興趣的朋友可以自己百度一下。

 
類的生命周期
        當我們編寫一個java的源文件后,經過編譯會生成一個后綴名為class的文件,這種文件叫做字節碼文件,只有這種字節碼文件才能夠在java虛擬機中運行,java類的生命周期就是指一個class文件從加載到卸載的全過程。
        一個java類的完整的生命周期會經歷加載、連接、初始化、使用、和卸載五個階段,當然也有在加載或者連接之后沒有被初始化就直接被使用的情況,如圖所示:

深入講解Java編程中類的生命周期

下面我們就依次來說一說這五個階段。
 
加載
       在java中,我們經常會接觸到一個詞——類加載,它和這里的加載并不是一回事,通常我們說類加載指的是類的生命周期中加載、連接、初始化三個階段。在加載階段,java虛擬機會做什么工作呢?其實很簡單,就是找到需要加載的類并把類的信息加載到jvm的方法區中,然后在堆區中實例化一個java.lang.Class對象,作為方法區中這個類的信息的入口。
       類的加載方式比較靈活,我們最常用的加載方式有兩種,一種是根據類的全路徑名找到相應的class文件,然后從class文件中讀取文件內容;另一種是從jar文件中讀取。另外,還有下面幾種方式也比較常用:
從網絡中獲?。罕热?0年前十分流行的Applet。
根據一定的規則實時生成,比如設計模式中的動態代理模式,就是根據相應的類自動生成它的代理類。
從非class文件中獲取,其實這與直接從class文件中獲取的方式本質上是一樣的,這些非class文件在jvm中運行之前會被轉換為可被jvm所識別的字節碼文件。
       對于加載的時機,各個虛擬機的做法并不一樣,但是有一個原則,就是當jvm“預期”到一個類將要被使用時,就會在使用它之前對這個類進行加載。比如說,在一段代碼中出現了一個類的名字,jvm在執行這段代碼之前并不能確定這個類是否會被使用到,于是,有些jvm會在執行前就加載這個類,而有些則在真正需要用的時候才會去加載它,這取決于具體的jvm實現。我們常用的hotspot虛擬機是采用的后者,就是說當真正用到一個類的時候才對它進行加載。
       加載階段是類的生命周期中的第一個階段,加載階段之后,是連接階段。有一點需要注意,就是有時連接階段并不會等加載階段完全完成之后才開始,而是交叉進行,可能一個類只加載了一部分之后,連接階段就已經開始了。但是這兩個階段總的開始時間和完成時間總是固定的:加載階段總是在連接階段之前開始,連接階段總是在加載階段完成之后完成。
 
連接
       連接階段比較復雜,一般會跟加載階段和初始化階段交叉進行,這個階段的主要任務就是做一些加載后的驗證工作以及一些初始化前的準備工作,可以細分為三個步驟:驗證、準備和解析。
驗證:當一個類被加載之后,必須要驗證一下這個類是否合法,比如這個類是不是符合字節碼的格式、變量與方法是不是有重復、數據類型是不是有效、繼承與實現是否合乎標準等等??傊@個階段的目的就是保證加載的類是能夠被jvm所運行。
準備:準備階段的工作就是為類的靜態變量分配內存并設為jvm默認的初值,對于非靜態的變量,則不會為它們分配內存。有一點需要注意,這時候,靜態變量的初值為jvm默認的初值,而不是我們在程序中設定的初值。jvm默認的初值是這樣的:
基本類型(int、long、short、char、byte、boolean、float、double)的默認值為0。
引用類型的默認值為null。
常量的默認值為我們程序中設定的值,比如我們在程序中定義final static int a = 100,則準備階段中a的初值就是100。
 解析:這一階段的任務就是把常量池中的符號引用轉換為直接引用。那么什么是符號引用,什么又是直接引用呢?我們來舉個例子:我們要找一個人,我們現有的信息是這個人的身份證號是1234567890。只有這個信息我們顯然找不到這個人,但是通過公安局的身份系統,我們輸入1234567890這個號之后,就會得到它的全部信息:比如安徽省黃山市余暇村18號張三,通過這個信息我們就能找到這個人了。這里,123456790就好比是一個符號引用,而安徽省黃山市余暇村18號張三就是直接引用。在內存中也是一樣,比如我們要在內存中找一個類里面的一個叫做show的方法,顯然是找不到。但是在解析階段,jvm就會把show這個名字轉換為指向方法區的的一塊內存地址,比如c17164,通過c17164就可以找到show這個方法具體分配在內存的哪一個區域了。這里show就是符號引用,而c17164就是直接引用。在解析階段,jvm會將所有的類或接口名、字段名、方法名轉換為具體的內存地址。
        連接階段完成之后會根據使用的情況(直接引用還是被動引用)來選擇是否對類進行初始化。
 
初始化
       如果一個類被直接引用,就會觸發類的初始化。在java中,直接引用的情況有:
通過new關鍵字實例化對象、讀取或設置類的靜態變量、調用類的靜態方法。
通過反射方式執行以上三種行為。
初始化子類的時候,會觸發父類的初始化。
作為程序入口直接運行時(也就是直接調用main方法)。
        除了以上四種情況,其他使用類的方式叫做被動引用,而被動引用不會觸發類的初始化。請看主動引用的示例代碼:

import java.lang.reflect.Field; import java.lang.reflect.Method;  class InitClass{   static {     System.out.println("初始化InitClass");   }   public static String a = null;   public static void method(){} }  class SubInitClass extends InitClass{}  public class Test1 {    /**    * 主動引用引起類的初始化的第四種情況就是運行Test1的main方法時    * 導致Test1初始化,這一點很好理解,就不特別演示了。    * 本代碼演示了前三種情況,以下代碼都會引起InitClass的初始化,    * 但由于初始化只會進行一次,運行時請將注解去掉,依次運行查看結果。    * @param args    * @throws Exception    */   public static void main(String[] args) throws Exception{   // 主動引用引起類的初始化一: new對象、讀取或設置類的靜態變量、調用類的靜態方法。   // new InitClass();   // InitClass.a = "";   // String a = InitClass.a;   // InitClass.method();        // 主動引用引起類的初始化二:通過反射實例化對象、讀取或設置類的靜態變量、調用類的靜態方法。   // Class cls = InitClass.class;   // cls.newInstance();        // Field f = cls.getDeclaredField("a");   // f.get(null);   // f.set(null, "s");      // Method md = cls.getDeclaredMethod("method");   // md.invoke(null, null);          // 主動引用引起類的初始化三:實例化子類,引起父類初始化。   // new SubInitClass();    } } 

        上面的程序演示了主動引用觸發類的初始化的四種情況。
 
        類的初始化過程是這樣的:按照順序自上而下運行類中的變量賦值語句和靜態語句,如果有父類,則首先按照順序運行父類中的變量賦值語句和靜態語句。先看一個例子,首先建兩個類用來顯示賦值操作:

public class Field1{   public Field1(){     System.out.println("Field1構造方法");   } } public class Field2{   public Field2(){     System.out.println("Field2構造方法");   } } 

下面是演示初始化順序的代碼:

class InitClass2{   static{     System.out.println("運行父類靜態代碼");   }   public static Field1 f1 = new Field1();   public static Field1 f2;  }  class SubInitClass2 extends InitClass2{   static{     System.out.println("運行子類靜態代碼");   }   public static Field2 f2 = new Field2(); }  public class Test2 {   public static void main(String[] args) throws ClassNotFoundException{     new SubInitClass2();   } } 

        上面的代碼中,初始化的順序是:第03行,第05行,第11行,第13行。第04行是聲明操作,沒有賦值,所以不會被運行。而下面的代碼:

class InitClass2{   public static Field1 f1 = new Field1();   public static Field1 f2;   static{     System.out.println("運行父類靜態代碼");   } }  class SubInitClass2 extends InitClass2{   public static Field2 f2 = new Field2();   static{     System.out.println("運行子類靜態代碼");   } }  public class Test2 {   public static void main(String[] args) throws ClassNotFoundException{     new SubInitClass2();   } } 

        初始化順序為:第02行、第05行、第10行、第12行,各位可以運行程序查看結果。
       在類的初始化階段,只會初始化與類相關的靜態賦值語句和靜態語句,也就是有static關鍵字修飾的信息,而沒有static修飾的賦值語句和執行語句在實例化對象的時候才會運行。
 
使用
       類的使用包括主動引用和被動引用,主動引用在初始化的章節中已經說過了,下面我們主要來說一下被動引用:

  • 引用父類的靜態字段,只會引起父類的初始化,而不會引起子類的初始化。
  • 定義類數組,不會引起類的初始化。
  • 引用類的常量,不會引起類的初始化。

被動引用的示例代碼:

class InitClass{   static {     System.out.println("初始化InitClass");   }   public static String a = null;   public final static String b = "b";   public static void method(){} }  class SubInitClass extends InitClass{   static {     System.out.println("初始化SubInitClass");   } }  public class Test4 {    public static void main(String[] args) throws Exception{   // String a = SubInitClass.a;// 引用父類的靜態字段,只會引起父類初始化,而不會引起子類的初始化   // String b = InitClass.b;// 使用類的常量不會引起類的初始化     SubInitClass[] sc = new SubInitClass[10];// 定義類數組不會引起類的初始化   } } 

        最后總結一下使用階段:使用階段包括主動引用和被動引用,主動飲用會引起類的初始化,而被動引用不會引起類的初始化。
        當使用階段完成之后,java類就進入了卸載階段。
 
卸載
       關于類的卸載,筆者在單例模式討論篇:單例模式與垃圾回收一文中有過描述,在類使用完之后,如果滿足下面的情況,類就會被卸載:

  • 該類所有的實例都已經被回收,也就是java堆中不存在該類的任何實例。
  • 加載該類的ClassLoader已經被回收。
  • 該類對應的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。

        如果以上三個條件全部滿足,jvm就會在方法區垃圾回收的時候對類進行卸載,類的卸載過程其實就是在方法區中清空類信息,java類的整個生命周期就結束了。

 
總結
        做java的朋友對于對象的生命周期可能都比較熟悉,對象基本上都是在jvm的堆區中創建,在創建對象之前,會觸發類加載(加載、連接、初始化),當類初始化完成后,根據類信息在堆區中實例化類對象,初始化非靜態變量、非靜態代碼以及默認構造方法,當對象使用完之后會在合適的時候被jvm垃圾收集器回收。讀完本文后我們知道,對象的生命周期只是類的生命周期中使用階段的主動引用的一種情況(即實例化類對象)。而類的整個生命周期則要比對象的生命周期長的多。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产主播欧美精品| 成人午夜小视频| 美日韩精品视频免费看| 国产精品丝袜白浆摸在线| 日韩电影中文字幕| 欧美性xxxx极品hd欧美风情| 久久综合色88| 日韩精品在线私人| 成人黄色av播放免费| 九九精品视频在线| 亚洲欧美三级在线| 欧美福利视频在线| 亚洲天堂av在线播放| 欧美性猛交xxxx久久久| 国产精品成人av在线| 久久天天躁狠狠躁夜夜躁2014| 永久555www成人免费| 国产视频精品免费播放| 色婷婷综合久久久久中文字幕1| 91高潮精品免费porn| 亚洲第一区中文字幕| 日本精品免费一区二区三区| 国产精品福利无圣光在线一区| 亚洲第一网站男人都懂| 中文字幕精品一区二区精品| 欧美日韩亚洲一区二| 国产一区二区三区在线看| 欧美日韩中文字幕日韩欧美| 自拍偷拍亚洲在线| 57pao成人永久免费视频| 亚洲桃花岛网站| 国产精品天天狠天天看| 欧美日韩在线看| 久久精品中文字幕一区| 日韩一区二区在线视频| 久久久精品久久久久| 亚洲一二三在线| 国产91露脸中文字幕在线| 18性欧美xxxⅹ性满足| 日韩av三级在线观看| 亚洲аv电影天堂网| 亚洲国产99精品国自产| 亚洲第一精品电影| 亚洲裸体xxxx| 欧美精品久久久久久久久| 久久国产精品影片| 国产成人福利网站| 日本精品va在线观看| 欧美巨乳在线观看| 欧美视频在线视频| 日本亚洲欧洲色α| 精品视频在线播放免| 91tv亚洲精品香蕉国产一区7ujn| 久久在线观看视频| 亚洲精品久久久久中文字幕欢迎你| 欧美精品激情blacked18| 色悠久久久久综合先锋影音下载| 在线播放亚洲激情| 清纯唯美亚洲激情| 亚洲高清不卡av| 欧美日韩亚洲精品一区二区三区| 欧美激情视频播放| 久久久在线观看| 亚洲国产精品免费| 国产精品久久久久久av福利| 久久久91精品国产| 欧美成人午夜激情在线| 日韩av电影在线播放| 亚洲一区二区自拍| 成人性生交大片免费看视频直播| 国产精品99一区| 青青a在线精品免费观看| 91在线观看免费高清完整版在线观看| 国产精品影片在线观看| 日韩av在线影院| 亚洲激情在线视频| 久久97精品久久久久久久不卡| 久久伊人91精品综合网站| 久久久久久久国产精品| 美女少妇精品视频| 91久久久亚洲精品| 日韩电影在线观看永久视频免费网站| 91久久精品美女高潮| 日韩精品视频在线观看网址| 美女久久久久久久久久久| 亚洲综合成人婷婷小说| 中文字幕亚洲欧美日韩在线不卡| 国产精品扒开腿做爽爽爽的视频| 日韩在线视频中文字幕| 青青草成人在线| 欧美大片在线免费观看| 国产精品成人av性教育| 亚洲国产精品热久久| 少妇激情综合网| 欧美理论片在线观看| 不卡av在线网站| 日韩电影中文字幕av| 8090理伦午夜在线电影| 日韩大片在线观看视频| 久久久国产精品视频| 国产91成人video| 国产一区二区三区在线免费观看| 欧美老女人bb| 九九热这里只有精品6| 在线日韩中文字幕| 亚洲免费一级电影| 国产成人精品久久二区二区91| 欧美性生交xxxxxdddd| 一区二区三区高清国产| 国产一区二区丝袜高跟鞋图片| 日韩电影大全免费观看2023年上| 欧美另类99xxxxx| 午夜精品国产精品大乳美女| 性欧美亚洲xxxx乳在线观看| 欧美日韩一区二区三区在线免费观看| 欧美亚洲国产日韩2020| 成人动漫网站在线观看| 国产在线视频欧美| yellow中文字幕久久| 精品国产网站地址| 热门国产精品亚洲第一区在线| 中文字幕av一区二区三区谷原希美| 伊人伊成久久人综合网小说| 日韩久久精品电影| 日韩精品视频免费专区在线播放| 欧美丰满老妇厨房牲生活| 久久免费视频网站| 久久99热这里只有精品国产| 国产视频在线一区二区| 97香蕉超级碰碰久久免费的优势| 一区二区三区视频在线| 亚洲国产毛片完整版| 国产精品吊钟奶在线| 亚洲国内精品在线| 日韩av三级在线观看| 欧美壮男野外gaytube| 久久91精品国产91久久久| 国内精品久久久久久中文字幕| 国产一区二区三区日韩欧美| 欧美人与性动交| 日韩欧美a级成人黄色| 日韩高清av一区二区三区| 国产精品免费久久久久久| 国产成人av网址| 亚洲一区二区少妇| 这里只有精品在线播放| 麻豆国产精品va在线观看不卡| 亚洲国产精品va在线看黑人动漫| 777国产偷窥盗摄精品视频| 中文字幕无线精品亚洲乱码一区| 久久国产精品影视| 欧美视频第一页| 国产美女久久精品香蕉69| 国产精品久久久久久中文字| 中文字幕亚洲一区在线观看| 亚洲成人999| 热久久免费视频精品| 亚洲精品永久免费精品| 日韩一区在线视频| 亚洲国产私拍精品国模在线观看| 亚洲人永久免费| 国产在线拍偷自揄拍精品| 成人做爰www免费看视频网站| 亚洲在线免费视频|