【Java基礎】Java對象的生命周期

【Java基礎】Java對象的生命周期

一、概述

一個類通過編譯器將一個Java文件編譯為Class字節碼文件,然后通過JVM中的解釋器編譯成不同操作系統的機器碼。雖然操作系統不同,但是基于解釋器的虛擬機是相同的。java類的生命周期就是指一個class文件加載到類文件注銷整個過程。

一個java類的完整的生命周期會經歷加載-連接-初始化-使用-卸載五個階段,當然也有在加載或連接之后沒有被初始化就直接被使用的情況,類加載的過程如下圖:

在這里插入圖片描述

二、加載(loading)

java類生命周期加載(loading)是有類加載器完成(類加載器分為:BootstrapClassLoader,ExtClassLoader,AppClassLoader),類的class二進制文件讀取到內存后,并將其保存到方法區內,然后就創建一個java.lang.Class類型的對象。類被加載入JVM中,同一個類只被載入一次。加載是類加載的第一個環節。

java生命周期加載(loading)階段主要做三件事

  1. 類加載器(ClassLoader)通過一個類的全稱獲取二進制Class文件,加載到JVM內存中(如果已經獲取過則直接返回其Class對象)。
  2. 將字節流所代表的靜態存儲結構轉化為JVM方法區的運行時數據結構。
  3. 在內存中生產一個代表此類的java.lang.Class的對象,作為訪問這個類的入口。

二、連接(Linking)

當類被加載之后,系統為了生成一個對應的java.lang.Class對象,接著將會進入連接階段,連接階段會負載把類的二進制數據合并到JVM的運行狀態中。類的連接可以分為如下三個階段:

  1. 驗證:確保java類型的數據格式正確并使用與jvm使用;驗證作為連接階段的第一個階段,這個階段確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。

    驗證包含一下內容

    • 文件格式驗證:如是否以魔數 0xCAFEBABE 開頭、主、次版本號是否在當前虛擬機處理范圍之內、常量合理性驗證等。此階段保證輸入的字節流能正確地解析并存儲于方法區之內,格式上符合描述一個 Java類型信息的要求;
    • 元數據驗證:是否存在父類,父類的繼承鏈是否正確,抽象類是否實現了其父類或接口之中要求實現的所有方法,字段、方法是否與父類產生矛盾等。第二階段,保證不存在不符合 Java 語言規范的元數據信息;
    • 字節碼驗證:通過數據流和控制流分析,確定程序語義是合法的、符合邏輯的。例如保證跳轉指令不會跳轉到方法體以外的字節碼指令上;
    • 符號引用驗證:在解析階段中發生,保證可以將符號引用轉化為直接引用。

    可以考慮使用 -Xverify:none 參數來關閉大部分的類驗證措施,以縮短虛擬機類加載的時間。

  2. 準備 :為該類分配內存;就是為類的靜態變量分配內存并設為jvm默認的初值,對于非靜態的變量,則不會為它們分配內存。靜態變量的初值是由JVM自動分配初始值。

    JVM默認的初值如下:

    • 內存分配的僅包括類變量(static),而不包括實例變量,實例變量會在對象實例化時隨著對象一塊分配在Java堆中;
    • 設置的初始值通常情況下是數據類型默認的零值(如0、0L、null、false等),而不是被在Java代碼中被顯式地賦予的值;
    • 對基本數據類型來說,對于類變量(static)和全局變量,如果不顯式地對其賦值而直接使用,則系統會為其賦予默認的零值,而對于局部變量來說,在使用前必須顯式地為其賦值,否則編譯時不通過。
    • 對于同時被static和final修飾的常量,必須在聲明的時候就為其顯式地賦值,否則編譯時不通過;而只被final修飾的常量則既可以在聲明時顯式地為其賦值,也可以在類初始化時顯式地為其賦值,總之,在使用前必須為其顯式地賦值,系統不會為其賦予默認零值。
    • 如果在數組初始化時沒有對數組中的各元素賦值,那么其中的元素將根據對應的數據類型而被賦予默認的零值。
  3. 解析:解析階段就是虛擬機將常量池中的符號引用轉化為直接引用的過程。

    • 符號引用

      符號引用是一個字符串,它給出了被引用的內容的名字并且可能會包含一些其他關于這個被引用項的信息——這些信息必須足以唯一的識別一個類、字段、方法。這樣,對于其他類的符號引用必須給出類的全名。對于其他類的字段,必須給出類名、字段名以及字段描述符。對于其他類的方法的引用必須給出類名、方法名以及方法的描述符。

    • 直接引用可以是以下三種情況

      1. 直接指向目標的指針(比如,指向“類型”【Class對象】、類變量、類方法的直接引用可能是指向方法區的指針)
      2. 相對偏移量(比如,指向實例變量、實例方法的直接引用都是偏移量)
      3. 個能間接定位到目標的句柄 直接引用是和虛擬機的布局相關的,同一個符號引用在不同的虛擬機實例上翻譯出來的直接引用一般不會相同。如果有了直接引用,那引用的目標必定已經被加載入內存中了

    解析階段可能開始于初始化之前,也可能在初始化之后開始,虛擬機會根據需要來判斷,到底是在類被加載器加載時就對常量池中的符號引用進行解析(初始化之前),還是等到一個符號引用將要被使用前才去解析它(初始化之后)

    解析主要分為兩種情況

    1. 類或接口的解析:判斷所要轉化成的直接引用是對數組類型,還是普通的對象類型的引用,從而進行不同的解析。
    2. 字段解析:對字段進行解析時,會先在本類中查找是否包含有簡單名稱和字段描述符都與目標相匹配的字段,如果有,則查找結束;如果沒有,則會按照繼承關系從上往下遞歸搜索該類所實現的各個接口和它們的父接口,還沒有,則按照繼承關系遞歸搜索其父類,直至查找結束。

    解析階段的靜態綁定和動態綁定:

    • 靜態綁定(static binding):也叫前期綁定,在程序執行前,該方法就能夠確定所在的類,此時由編譯器或其它連接程序實現,比如構造方法或者被static或final修飾的。
    • 動態綁定(auto binding):也叫后期綁定,在運行時,虛擬機根據具體對象的類型進行綁定,或者說是只有對象在虛擬機中創建了之后,才能確定方法屬于哪一個對象,比如含有泛型的。

三、初始化(Initialization)

執行靜態變量的初始化和靜態Java代碼塊,并初始化已設置好的變量值。需要注意的是加載、驗證和裝備階段只會進行一次,而初始化是可以重復進行的。在準備階段,類變量已經被初始化過一次系統提供的默認值,而在初始化階段,則是根據java代碼中實際指定的值去初始化類變量和其它內容。

類的初始化即是執行類構造器<clinit>()方法的過程,規則如下:

  1. <clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊中的語句合并產生的,編譯器收集的順序是由語句在源文件中出現的順序所決定的,靜態語句塊中只能訪問到定義在靜態語句塊之前的變量,定義在它之后的變量,則只可以賦值,而不能訪問。
  2. ()方法與實例構造器()方法(類的構造函數)不同,它不需要顯式地調用父類構造器,虛擬機會保證在子類的()方法執行之前,父類的()方法已經執行完畢。因此,在虛擬機中第一個被執行的()方法的類肯定是java.lang.Object
  3. <clinit>()方法對于類或接口來說并不是必須的,如果一個類中沒有靜態語句塊,也沒有對類變量的賦值操作,那么編譯器可以不為這個類生成<clinit>()方法。
  4. 接口中不能使用靜態語句塊,但仍然有類變量(final static)初始化的賦值操作,因此接口與類一樣會生成()方法。但是接口魚類不同的是:執行接口的()方法不需要先執行父接口的()方法,只有當父接口中定義的變量被使用時,父接口才會被初始化。另外,接口的實現類在初始化時也一樣不會執行接口的()方法。
  5. 虛擬機會保證一個類的()方法在多線程環境中被正確地加鎖和同步,如果多個線程同時去初始化一個類,那么只會有一個線程去執行這個類的()方法,其他線程都需要阻塞等待,直到活動線程執行()方法完畢。如果在一個類的()方法中有耗時很長的操作,那就可能造成多個線程阻塞,在實際應用中這種阻塞往往是很隱蔽的。

觸發對象初始化的場景:

  1. 通過new關鍵字實例化對象、讀取或設置類的靜態變量、調用類的靜態方法。
  2. 通過反射方式實例化對象,如Class.forName()方法。
  3. 初始化子類的時候,會觸發父類的初始化。
  4. 虛擬機啟動時,初始化一個執行主類(也就是直接調用main方法)。
  5. 使用(反)序列化機制創建對象。
  6. 使用JDK7的動態語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結果REF_getStaticREF_putStaticRE_invokeStatic的方法句柄,并且這個方法句柄對應的類沒有進行初始化,則需要先觸發其初始化。

初始化的原則: 按照順序自上而下運行類中的變量賦值語句和靜態語句,如果有父類,則首先按照順序依次遞歸運行父類中的變量賦值語句和靜態語句。

四、使用(Using)

當一個對象初始化完成后就生成了一個對象的實例。

  1. 訪問類變量和方法不需要實例化
  2. 靜態代碼塊只會被調用一次,而實例的代碼塊則是每次初始化調用一次
  3. 通過final修飾符可以防止類被繼承或者變量的值被修改
  4. 設置訪問權限限制其它對象的訪問

實例化一個類大概有四種途徑

  1. New操作符;
  2. 調用Class或者Java.lang.reflect.Constructor對象的newInstance()方法;
  3. 調用任何現有對象的Clone()方法;
  4. 通過java.io.ObjectInputStream類的getObject()方法反序列化;

實例化步驟:

  1. 在堆中為保存對象的實例變量分配內存;
  2. 為實例變量初始化為默認的初始值;
  3. 為實例變量賦正確的初始值,有三種技術完成賦值:
    • 如果對象是clone() 創建的,jvm把原實例變量中的值拷貝到新對象中;
    • 如果是通過ObjectInputStream類的readObject()調用反序列化的,jvm從輸入流中讀取的值來初始化實例變量;
    • jvm調用對象的實例化方法把對象的實例變量初始化為正確的初始值;

五、卸載(Unloading)

jvm實現必須具有某種自動堆存儲管理策略,大部分是使用垃圾收集器。如果類聲明了 void finalize()方法,垃圾收集器在釋放實例內存前會執行這個方法。垃圾收集器自動調用的finalize()方法拋出的任何異常都將被忽略。

從jvm中卸載類型,很多情況,jvm中類的生命周期和對象的生命周期很相似。jvm如何判斷動態裝載的類型是否仍然被程序使用,其判斷方式和判斷對象是否仍然被使用很相似。在類使用完之后如果滿足下面的情況,類就會被卸載:

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

如果以上三個條件全部滿足,jvm就會在方法區垃圾回收的時候對類進行卸載,類的卸載過程其實就是在方法區中清空類信息,java類的整個生命周期就結束了。如果使用啟動類裝載器裝載的類型永遠都是可觸及的,所以永遠不會被卸載。只有使用用戶定義的類裝載器裝載的類型才會變成不可觸及,才會被卸載。

六、總結

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39950.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39950.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39950.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu安裝MySQL Server提示Depends: mysql-server-5.5怎么解決

在 Ubuntu 安裝 MySQL Server 時出現 Depends: mysql-server-5.5 的錯誤通常是因為系統中沒有找到所需的軟件包版本。這可能是因為軟件包源中沒有對應的版本或者軟件包版本沖突等原因。解決這個問題的方法如下&#xff1a; 更新軟件包列表&#xff1a; 在終端中運行以下命令&a…

python控制obs實現無縫切換場景!obs-websocket-py

前言 最近一直在研究孿生數字人wav2lip。目前成果可直接輸入高清嘴型&#xff0c;2070顯卡1分鐘音頻2.6分鐘輸出。在直播邏輯上可以做到1比1.3這樣&#xff0c;所以現在開始研究直播。在邏輯上涉及到了無縫切換&#xff0c;看到csdn上有一篇文章還要vip解鎖。。。那自己研究吧…

臨時用工小程序:一款便捷的用工管理軟件

隨著企業對人力資源需求的不斷增長&#xff0c;臨時用工需求也日益旺盛。為了滿足這一需求&#xff0c;我們研發了一款名為“臨時用工小程序”的軟件系統&#xff0c;旨在幫助企業實現臨時用工的高效管理。 一、技術棧介紹 后端技術棧 本系統采用Java語言作為開發語言&#…

尚硅谷MySQL筆記 3-9

我不會記錄的特別詳細 大體框架 基本的Select語句運算符排序與分頁多表查詢單行函數聚合函數子查詢 第三章 基本的SELECT語句 SQL分類 這個分類有很多種&#xff0c;大致了解下即可 DDL&#xff08;Data Definition Languages、數據定義語言&#xff09;&#xff0c;定義了…

項目難點:解決IOS調用起軟鍵盤之后頁面樣式布局錯亂問題

需求背景 &#xff1a; 開發了一個問卷系統重構項目&#xff0c;剛開始開發的為 PC 端&#xff0c;其中最頭疼的一點無非就是 IE 瀏覽器的兼容適配性問題&#xff1b; 再之后項目經理要求開發移動端&#xff0c;簡單的說就是寫 H5 頁面&#xff0c;到時候會內嵌在 App 應用、辦…

multiple definition of......first defined here

一、背景 環境&#xff1a; 銀河麒麟–ARM–GCC7.4.0 寫了一個動態庫&#xff0c;依賴opencv和freeImage等第三方庫&#xff0c;用cmake進行編譯。原本在centos6-x86-gcc7.5.0上面進行編譯非常的順利&#xff0c;但是拿到麒麟arm上面編譯就提示了這個錯誤&#xff1a;這個報錯…

Python conda命令

Windows下 Anaconda Prompt 這個東西就是用來管理Anaconda的&#xff0c;使用的是conda這樣的一種命令 在Linux中&#xff0c;可以直接在終端中輸入conda 命令 可以使用conda命令創建新的python環境&#xff08;python版本&#xff0c;包&#xff09;&#xff0c;新的環境與原…

Ruby軟件外包開發語言特點

Ruby 是一種動態、開放源代碼的編程語言&#xff0c;它注重簡潔性和開發人員的幸福感。在許多方面都具有優點&#xff0c;但由于其動態類型和解釋執行的特性&#xff0c;它可能不適合某些對性能和類型安全性要求較高的場景。下面和大家分享 Ruby 語言的一些主要特點以及適用的場…

【C語言】動態通訊錄 -- 詳解

?前言 前面詳細介紹了靜態版通訊錄【C語言】靜態通訊錄 -- 詳解_炫酷的伊莉娜的博客-CSDN博客&#xff0c;但是靜態版通訊錄的空間是無法被改變的&#xff0c;而且空間利用率也不高。為了解決靜態通訊錄這一缺點&#xff0c;這時就要有一個能夠隨著存入聯系人數量的增加而增大…

Ansys Zemax | 手機鏡頭設計 - 第 1 部分:光學設計

本文是 3 篇系列文章的一部分&#xff0c;該系列文章將討論智能手機鏡頭模組設計的挑戰&#xff0c;從概念、設計到制造和結構變形的分析。本文是三部分系列的第一部分&#xff0c;將專注于OpticStudio中鏡頭模組的設計、分析和可制造性評估。&#xff08;聯系我們獲取文章附件…

Vue緩存路由組件

目錄 一、使用 一、使用 作用&#xff1a;讓不展示的路由組件保持掛載&#xff0c;不被銷毀 <template><div><h2>Home組件內容</h2><div><ul class"nav nav-tabs"><li><router-link class"list-group-item"…

安防監控視頻云存儲平臺EasyNVR通道頻繁離線的原因排查與解決

安防視頻監控匯聚EasyNVR視頻集中存儲平臺&#xff0c;是基于RTSP/Onvif協議的安防視頻平臺&#xff0c;可支持將接入的視頻流進行全平臺、全終端分發&#xff0c;分發的視頻流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。為了滿足用戶的集成與二次開發需求&#xf…

OpenCV(二)——圖像基本處理(二)

目錄 2.圖像的幾何變換 2.1 圖像平移 2.2 圖像縮放 2.3 圖像旋轉 2.4 仿射變換 2.5 透視變換

企業計算機服務器遭到了locked勒索病毒攻擊如何解決,勒索病毒解密

網絡技術的不斷發展&#xff0c;也為網絡安全埋下了隱患&#xff0c;近期&#xff0c;我們收到很多企業的求助&#xff0c;企業的計算機服務器遭到了locked勒索病毒的攻擊&#xff0c;導致企業的財務系統內的所有數據被加密無法讀取&#xff0c;嚴重影響了企業的正常運行。最近…

如何通過觀測云的RUM找到前端加載的瓶頸--可觀測性入門篇

聲明與保證 本文寫作于2023年6月&#xff0c;性能優化的評價標準和優化方式僅適用于當前觀測云控制臺&#xff0c;當然隨著產品迭代及技術更新&#xff0c;本文也會應要求適當更新。 創建、修訂時間創建修改人版本2023/6/24觀測云***v1.0.0 1.網站性能評價的發展史&#xff…

PHP“深入淺出”淘寶商品詳情數據接口獲取方法,淘寶API申請指南

獲取淘寶商品詳情數據的方法如下&#xff1a; 確定監控對象&#xff0c;通常是與自己店鋪的商品相似的競品&#xff0c;通過在淘寶商品詳情頁的URL中獲取商品ID&#xff0c;進而獲取商品的詳情數據。通過API接口獲取商品詳情數據&#xff0c;申請開發者賬號并獲取授權訪問&…

打開vim的語法高亮

在一個Ubuntu中自帶的vim版本是8.2.4919&#xff0c;默認就是開始了語法高亮的&#xff0c;打開一個Java文件效果如下&#xff1a; 它不僅僅對Java文件有語法高亮&#xff0c;對很多的文件都有&#xff0c;比如vim的配置文件也有語法高亮&#xff0c;有語法高亮時讀起來會容易…

DNNGP模型解讀-early stopping 和 batch normalization的使用

一、考慮的因素&#xff08;僅代表個人觀點&#xff09; 1.首先我們看到他的這篇文章所考慮的不同方面從而做出的不同改進&#xff0c;首先考慮到了對于基因組預測的深度學習方法的設計 &#xff0c;我們設計出來這個方法就是為了基因組預測而使用&#xff0c;這也是主要目的&…

排序算法-冒泡排序(C語言實現)

簡介&#x1f600; 冒泡排序是一種簡單但效率較低的排序算法。它重復地掃描待排序元素列表&#xff0c;比較相鄰的兩個元素&#xff0c;并將順序錯誤的元素交換位置&#xff0c;直到整個列表排序完成。 實現&#x1f9d0; 以下內容為本人原創&#xff0c;經過自己整理得出&am…

WAVE SUMMIT2023六大分會場同步開啟,飛槳+文心大模型加速區域產業智能化!

由深度學習技術及應用國家工程研究中心主辦、百度飛槳和文心大模型承辦的WAVE SUMMIT深度學習開發者大會2023將于8月16日重磅來襲&#xff01;屆時上海、廣州、深圳、成都、南昌和寧波六大分會場將同步開啟&#xff01; 分會匯聚區域產業大咖、科研機構專家、知名學者和技術大…