1. 程式人生 > >深入理解Android之Java虛擬機器Dalvik

深入理解Android之Java虛擬機器Dalvik

一、背景

這個選題很大,但並不是一開始就有這麼高大上的追求。最初之時,只是源於對Xposed的好奇。Xposed幾乎是定製ROM的神器軟體技術架構或者說方法了。它到底是怎麼實現呢?我本意就是想搞明白Xposed的實現原理,但隨著程式碼研究的深入,我發現如果不瞭解虛擬機器的實現,而僅簡單停留在Xposed的呼叫流程之上,那真是對Xposed最大的不敬了。另外,歪果仁為什麼能寫出Xposed?Android上的Java虛擬機器對他們來說應該也是相對陌生的,何以他們能做而我們沒有人搞出這樣的東西?

所以,在研究Xposed之後,我決定把虛擬機器方面的東西也來研究一番。誠如我在很多場合中提到的關於Android學習的三個終極問題(其實對其他各科學習也適用):學什麼?怎麼學?學到什麼程度為止?關於這三個問題,以本次研究的情況來看,回答如下:

  • 學習目標是:按順序是dalvik虛擬機器,然後是Xposed針對dalvik的實現,然後是art虛擬機器。
  • 學習方法:VM原理配合具體實現,以程式碼為主。Java VM有一套規範,各公司具體的VM實現必須遵守此規範。所以對VM學習而言,規範很重要,它是不變的,而程式碼實現只不過是該規範的一種實現罷了。這裡也直接體現了我提出的關於專業知識學習的一句警語“基於Android,高於Android”。對VM而言,先掌握規範才是最最重要和核心的事情。
  • 學到什麼程度為止:對於dalvik虛擬機器,我們以學會一段Java程式從程式碼,到位元組碼,最後到如何被VM載入並執行它為止。關於dalvik的記憶體管理我們不會介紹。對於XPosed,基於dalvik+selinux環境的程式碼我們會全部分析。對於ART,由於它是Google未來較長一段時期的重點,所以我們也會圍繞它做更多的分析,諸如記憶體管理怕是肯定會加上的。

除了這三個問題,其實還有一個隱含的疑問,學完之後有什麼用呢?

  • 這個問題的答案要看各位的需求了。從本人角度來看,我就是想知道Xposed是怎麼實現的。另外,如果瞭解虛擬機器實現的話,我還想定製它,使得它在智慧POS領域變得更安全一點。
  • 當然,我自己有一個比較高大上的夢想,就是我一直想寫Linux Kernel方面的書,而且我自認為已經找到了一個絕妙的學習它的入手點(我在魅族做分享的時候介紹過。到今天為止一年多過去了,不知道當初的有心人是否藉此脫引而出,如果有的話也請和大家分享下你的學習經歷)。Anyway,從目前的工作環境和需求來看,VM是當前更好的學習目標。

言歸正傳,現在開始正式介紹dalvik,請牢記關於它的學習目標和學習程度。

你也可以下載本專題對應的demo程式碼用於學習。

二、Class、dex、odex檔案結構

2.1  Class檔案結構總覽

Class檔案是理解Vm實現的關鍵。關於Class檔案的結構,這裡介紹的內容直接參考JVM規範,因為它是最權威的資料。

Oracle的JVM SE7官方規範:https://docs.oracle.com/javase/specs/jvms/se7/html/

還算很有良心,純網頁版的,也可以下載PDF版。另外,周志明老師曾經翻譯過中文版的JVM規範,網上可搜尋到。

作為分析Class檔案的入口,我在Demo示例中提供了一個特別簡單的例子,程式碼如圖1所示:

TestMain類的程式碼簡單到不行,此處也不擬多說,因為沒有特殊之處。

當我們用eclipse編譯這個類後,將得到bin/com/test/TestMain.class。這個TestMain.class就是我們要分析的Class檔案了。

Class檔案到底是什麼東西?我覺得一種通俗易懂的解釋就是:

  1. *.java檔案是人編寫的,給人看的。
  2.  *.class是通過工具處理*.java檔案後的產物,它是給VM看的,給VM操作的

在某種哲學意義上看,java原始檔和處理得到的class檔案是同一種東西......

那麼,這個給VM使用的class檔案,其內部結構是怎樣的呢?Jvm規範很聰明,它通過一個C的資料結構表達了class檔案結構。這個資料結構如圖2所示:

請大家務必駐足停留片刻,因為搞清楚圖2的內容對後續的學習非常關鍵。圖2的ClassFile這個資料結構真得是太容易理解了。相比那些native的二進位制程式而言,ClassFile的組織結構和Java原始碼的組織結構匹配度非常高,以致於我第一眼看到這個結構體時,我覺得自己差不多就理解了它:

  • 比如,類的是public的還是final的,還是interface,就由access_flags來表示。其具體取值我覺得都不用管,程式碼中用得是名字諸如ACC_XXX這樣得的標誌位來表示,一看知道是啥玩意兒。
  • Java類中定義的域(成員變數),方法等都有對應的資料結構來表達,而且還是個陣列。
  • 唯一有點特別之處的是常量池。什麼東西會放在常量池呢?最容易想到的就是字串了。對頭,這個Java原始碼中的類名,方法名,變數名,居然都是以字串形式儲存在常量池中。所以,圖2中的this_class和super_class分別指向兩個字串,代表本類的名字和基類的名字。這兩個字串儲存在常量池中,所以this_class和super_class的型別都是u2(索引,代表長度為2個位元組)。

Class檔案用javap工具可以很好得解析成圖2那樣的格式,我這裡替大家解析了一把,結果如圖3所示(先顯示部分內容):

注意,解析方法為:javap -verbose xxxx.class

先來看看常量池。

2.1.1  常量池介紹

常量池看起來陌生,其實簡單得要死。注意,count_pool_count是常量池陣列長度+1。比如,假設某個Class檔案常量池只有4個元素,那麼count_pool_count=5)。

javap解析class檔案的時候,常量池的索引從1算起,0預設是給VM自己用得,一般不顯示0這一項。這也是為什麼圖3中常量池第一個元素以#1開頭。所以,如果count_pool_count=5的話,真正有用的元素是從count_pool[1]到count_pool[4]。

常量池陣列的元素型別由下面的程式碼表示:

cp_info { //特別注意,這是介紹的cp_info是相關元素型別的通用表達。
    u1 tag;   //tag為1個位元組長。不論cp_info具體是哪種,第一個位元組一定代表tag
    u1 info[]; //其他資訊,長度隨tag不同而不同
}

//tag取值,先列幾個簡單的:
tag=7 <==info代表這個cp_info是CONSTANT_Class_info結構體
tag=9<==info代表CONSTANT_Fieldrefs_info結構體
tag=10<==info代表CONSTANT_Methodrefs_info結構體
tag=8<==info代表CONSTANT_String_info結構體
tag=1<==info代表CONSTANT_Utf8_info結構體

在JVM規範中,真正代表字串的資料結構是CONSTANT_Utf8_info結構體,它的結構如下程式碼所示:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;  //下面就是儲存UTF8字串的地方了
    u1 bytes[length];
}

大家看圖3中常量池的內容,比如#2=Utf8 com/test/TestMain  這行表示:

陣列第二個元素的型別是CONSTANT_Utf8_info,字串為“com/test/TestMain”

下面我們看幾個常用的常量池元素型別

(1)  CONSTANT_Class_info

這個型別是用於描述類資訊的,此處的類資訊很簡單,就是類名(也就是代表類名的字串)

CONSTANT_Class_info {
    u1 tag;   //tag取值為7,代表CONSTANT_Class_info
    u2 name_index;  //name_index表示代表自己類名的字串資訊位於於常量池陣列中哪一個,也就是索引
}

唉,夠懶的,name_index對應的那個常量池元素必須是CONSTANT_Utf8_info,也就是字串。圖3中的例子,咱們再看看:

#1 = Class  #2  //com/test/TestMain

#2 = Utf8  com/test/TestMain

這說明:

  1. 常量池第一個元素型別為Class_info,它對應的name_index取值為2,表示使用第2個元素
  2. 常量池第二個元素型別為Utf8  內容為“com/test/TestMain”
  3. #1最後的//表示註釋,它把第二行的字串內容直接搬過來,方便我們檢視
(2)  CONSTANT_NameAndType_Info

這個結構也是常量池資料結構中中比較重要的一個,幹什麼用得呢?恩,它用來描述方法/成員名以及型別資訊的。有點JNI基礎的童鞋相信不難明白,在JNI中,一個類的成員函式或成員變數都可以由這個類名字串+函式名字串+引數型別字串+返回值型別來確定(如果是成員變數,就是類名字串+變數名字串+型別字串)來表達。既然是字串,那麼NameAndType_Info也就是儲存了對應字串在常量池陣列中的索引:

CONSTANT_NameAndType_info {
   u1 tag;
   u2 name_index;  //方法名或域名對應的字串索引
   u2 descriptor_index; //方法資訊(引數+返回值),或者成員變數的資訊(型別)對應的字串索引
}
//還是來看圖3中的例子吧
#13 = Utf8  ()V
#15 = NameAnType  #16.#13  //合起來就是test.()V 函式名是test,引數和返回值是()V
#16=Utf8 test

太簡單了,都不惜得說...,請大家自行解析#25這個常量池元素的內容,一定要做喔!

注意,對於建構函式和類初始化函式來說,JVM要求函式名必須是<init>和<cinit>。當然,這兩個函式是編譯器生成的。

(3)  CONSTANT_MethodrefInfo三兄弟

Methodref_Info還有兩個兄弟,分別是Fieldref_Info,InterfaceMethodref_Info,他們三用於描述方法、成員變數和介面資訊。剛才的NameAndType_Info其實已經描述了方法和成員變數資訊的一部分,唯一還缺的就是沒有地方描述它們屬於哪個類。而咱這三兄弟就補全了這些資訊。他們三的資料結構如圖4所示:

如此直白簡單,不解釋了。不放心的童鞋們請對照圖3的例子自行玩耍!

常量池先介紹到這,它還有一些有用的資訊,不過要等到後面我們碰到具體問題時再分析

2.1.2  Field和Method描述

剛才在常量池介紹中有提到Methodref_Info和Fieldref_Info,不過這兩個Info無非是描述了函式或成員變數的名字,引數,型別等資訊。但是真正的方法、成員變數資訊還包括比如訪問許可權,註解,原始碼位置等。對於方法來說,更重要的還包括其函式功能(即這個函式對應的位元組碼)。

在Java VM中,方法和成員變數的完整描述由如圖5所示的資料結構來表達的:

  • access_flags:描述諸如final,static,public這樣的訪問標誌
  • name_index:方法或成員變數名在常量池中對應的索引,型別是Utf8_Info
  • attribute_info:是域或方法中很重要的資訊。我們單獨用一節來介紹它。

2.1.3  attribute_info介紹

attribute_info結構體很簡單,如下程式碼所示:

attribute_info {//特別注意,這裡描述的attribute_info結構體也是具體屬性資料結構的通用表達
    u2 attribute_name_index;  //attribute_info的描述,指向常量池的字串
    u4 attribute_length;  //具體的內容由info陣列描述
    u1 info[attribute_length];
}

Java VM規範中,attribute型別比較多,我們重點介紹幾個,先來看代表一個函式實際內容的Code屬性。

(1)  Code屬性

代表Code屬性的資料結構如圖6所示:

  • 前2個成員變數就不多說了。屬於attribute的頭6個位元組,分別指向代表屬性名字串的常量池元素以及後續屬性資料的長度。注意,Code屬性的attribute_name_index所指向的那個Utf8常量池元素對應的字串內容就是“Code”,大家可參考圖3的#9。
  • max_stack和max_locals:虛擬機器在執行一個函式的時候,會為它建立一個運算元棧。執行過程中的引數啊,一些計算值啊等都會壓入棧中。max_stack就表示該函式執行時,這個棧的最大深度。這是編譯時就能確定的。max_locals用於描述這個方法最大的棧數和最大的本地變數個數。本地變數個數包括傳入的引數。
  • code_length和code:這個函式編譯成Java位元組碼後對應的位元組碼長度和內容。
  • exception_table_length:用來描述該方法對應異常處理的資訊。這塊我不打算講了,其實也蠻簡單,就是用start_pc表示異常處理時候從此方法對應位元組碼(由code[]陣列表示)哪個地方開始執行。
  • Code屬性本身還能包含一些屬性,這是由attributes_count和attributes陣列決定的。

來看個實際例子吧,如圖7所示(接著圖3的例子):

圖7中:

  • stack=2,locals=2,args_size=1。結合程式碼,main函式確實有一個引數,而且還有一個本地變數。注意,main函式是static的。如果對於類的非static函式,那麼locals的第0個元素代表this。
  • stack後面接下來的就是code陣列,也就是這個函式對應的執行程式碼。0表示code[]的索引位置。0:new:代表這個操作是new操作,此操作對應的位元組碼長度為3,所以下一個操作對應的位元組碼從索引3開始。
  • LineNumberTable也是屬性的一種,用於除錯,它將原始碼和位元組碼匹配了起來。比如line 7: 0這句話代表該函式位元組碼0那一個操作對應程式碼的第7行。
  • LocalVariableTable:它也是屬性一種,用於除錯,它用於描述函式執行時的變數資訊。比如圖7中的Start = 0:表示從code[]第0個位元組開始,Length = 13表示到從start=0到start+13個位元組(不包含第13個位元組,因為code陣列一共就12個位元組)這段範圍內,這個變數都有效(也就是這個變數的作用域),Slot=0表示這個變數在本地變量表中第一個元素,還記得前面提到的locals嗎?,name為“args”,表示這個引數的名字叫args,型別(由Signature表示)就是String陣列了。

請大家自行解析圖7中最後一行,看看能搞明白LocalVariableTable的含義不...

另外,Android SDK build Tools中的dx工具dump class檔案得到的資訊更全,大家可以試試。

使用方法是:dx --dump --debug xxx.class。

Class檔案先介紹到這,下面我們來看看Android平臺上的dex檔案。

2.2  Dex檔案結構和Odex

2.2.1  dex檔案結構簡介

Android平臺中沒有直接使用Class檔案格式,因為早期的Anrdroid手機記憶體,儲存都比較小,而Class檔案顯然有很多可以優化的地方,比如每個Class檔案都有一個常量池,裡邊儲存了一些字串。一串內容完全相同的字串很有可能在不同的Class檔案的常量池中存在,這就是一個可以優化的地方。當然,Dex檔案結構和Class檔案結構差異的地方還很多,但是從攜帶的資訊上來看,Dex和Class檔案是一致的。所以,你瞭解了Class檔案(作為Java VM官方Spec的標準),Dex檔案結構只不過是一個變種罷了(從學習到什麼程度為止的問題來看,如果不是要自己來解析Dex檔案,或者反編譯/修改dex檔案,我覺得大致瞭解下Dex檔案結構的情況就可以了)。圖8所示為Dex檔案結構的概貌:


有一點需要說明:傳統Class檔案是一個Java原始碼檔案會生成一個.Class檔案,而Android是把所有Class檔案進行合併,優化,然後生成一個最終的class.dex,如此,多個Class檔案裡如果有重複的字串,當把它們都放到一個dex檔案的時候,只要一份就可以了嘛。

dex頭部資訊中的magic取值為“dex\n035\0”

proto_ids:描述函式原型資訊,包括返回值,引數資訊。比如“test:()V”

methods_ids:函式資訊,包括所屬類及對應的proto資訊。比如

"Lcom.test.TestMain. test:()V",.前面是類資訊,後面屬於proto資訊

下面我們將示例TestMain.class轉換成dex檔案,然後再用dexdump工具看看它的結果,如圖9所示:

具體方法:

  • 先將.class檔案轉換成dex檔案,工具是sdk build-tools下的dx命令。dx --dex --debug --verbose-dump --output=test.dex com/test/TestMain.class,生成test.dex檔案。
  • 同樣,利用build-tools下的dexdump命令檢視,dexdump -d -l plain test.dex,得到圖9的結果

圖9中的dexdump結果其實比圖3還要清晰易懂。我們重點關注code段的內容(圖中紅框的部分):

  • registers:Dalvik最初目標是執行在以ARM做CPU的機器上的,ARM晶片的一個主要特點是暫存器多。暫存器多的話有好處,就是可以把運算元放在暫存器裡,而不是像傳統VM一樣放在棧中。自然,操作暫存器是比操作記憶體(棧嘛,其實就是一塊記憶體區域)快。registers變量表示該方法執行過程中會使用多少個暫存器。
  • ins:輸入引數對應的個數,outs:此函式內部呼叫其他函式,需要的引數個數。
  • insns:size:以4位元組為單位,代表該函式位元組碼的長度(類似Class檔案的code[]陣列)

Android官方文件:https://source.android.com/devices/tech/dalvik/dex-format.html

說實話,寫完這一小節的時候,我又反覆看了官方文件還有其他一些參考文件。很痛苦,主要是東西太多,而我們目前又沒有實際的問題,所以基本上是一邊看一邊忘!

恩。至少在這個階段,先了解到這個程度就好。後面會隨著學習的深入,有更多的深入知識,到時候根據需求再加進來。

2.2.2  odex介紹

再來看odex。odex是Optimized dex的簡寫,也就是優化後的dex檔案。為什麼要優化呢?主要還是為了提高Dalvik虛擬機器的執行速度。但是odex不是簡單的、通用的優化,而是在其優化過程中,依賴系統已經編譯好的其他模組,簡單點說:

  • 從Class檔案到dex檔案是針對Android平臺的一種優化,是一種通用的優化。優化過程中,唯一的輸入是Class檔案。
  • odex檔案就是dex檔案具體在某個系統(不同手機,不同手機的OS,不同版本的OS等)上的優化。odex檔案的優化依賴系統上的幾個核心模組(由BOOTCLASSPATH環境變數給出,一般是/system/framework/下的jar包,尤其是core.jar)。我個人感覺odex的優化就好像是把中那些本來需要在執行過程中做的類校驗、呼叫其他類函式時的解析等工作給提前處理了。

圖10給出了圖1所示示例程式碼得到的test.dex,然後利用dexopt得到test.odex,接著利用dexdump得到其內容,最後利用Beyond Compare比較這兩個檔案的差異。

圖10中,綠色框中是test.dex的內容,紅色框中是test.odex的內容,這也是兩個檔案的差異內容:

  • test.dex中,TestMain類僅僅是PUBLIC的,但test.odex則增加了VERIFIED和OPTIMIZED兩項。VERIFIED是表示該類被校驗過了,至於校驗什麼東西,以後再說。
  • 然後就是一些方法的不同了。優化後的odex檔案,一些位元組碼指令變成了xxx-quick。比如圖中最後一句程式碼對於的位元組碼中,未優化前invoke-virtual指令表示從method table指定項(圖中是0002)裡找到目標函式,而優化後的odex使用了invoke-virtual-quick表示從vtable中找到目標函式(圖中是000b)。

vtable是虛表的意思,一般在OOP實現中用得很多。vtable一定比methodtable快麼?那倒是有可能。我個人猜測:

  • method表應該是每個dex檔案獨有的,即它是基於dex檔案的。
  • 根據odex檔案的生成方法(後面會講),我覺得vtable恐怕是把dex檔案及依賴的類(比如Java基礎類,如Object類等)放一起進行了處理,最終得到一張大的vtable。這個odex檔案依賴的一些函式都放在vtable中。執行時直接呼叫指定位置的函式就好,不需要再解析了。以上僅是我的猜測。

1  http://mylifewithandroid.blogspot.com/2009/05/about-quick-method-invocation.html介紹了vtable的生成,大家可以看看

2  http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html 詳細描述了dex/odex指令的格式,大家有興趣可以做參考。

(1)  odex檔案的生成

前面曾經提到過,odex檔案的生成依賴於BOOTCLASSPATH提供的系統核心庫。以我們這個簡單的例子而言,core.jar是必須的(java基礎類大部分封裝在core.jar中)。另外,core.jar對應的core.odex檔案也需要。所有這些檔案我都已經上傳到示例程式碼倉庫的javavmtest/odex-test目錄下。然後執行dextest.sh指令碼。此指令碼內容如下:


            
           

相關推薦

深入理解AndroidJava虛擬機器Dalvik

一、背景這個選題很大,但並不是一開始就有這麼高大上的追求。最初之時,只是源於對Xposed的好奇。Xposed幾乎是定製ROM的神器軟體技術架構或者說方法了。它到底是怎麼實現呢?我本意就是想搞明白Xposed的實現原理,但隨著程式碼研究的深入,我發現如果不瞭解虛擬機器的實現,

深入理解AndroidJava Security第一部分

深入理解Android之Java Security(第一部分)從事Android工作4年以來,只有前1年不到的時間是用C++在開發東西(主要是開發DLNA元件,目前我已將它們全部開源,參考http://

深入理解AndroidJava Security第二部分(Final)

深入理解Android之Java Security(第二部分,最後)程式碼路徑:Security.java:libcore/lunl/src/main/java/java/security/TrustedCertificateStore.java:libcore /crypt

深入瞭解Java虛擬機器Java虛擬機器

        與程式計數器(想了解計數器看我上一篇部落格)一樣,Java虛擬機器棧也是執行緒私有的,他的生命週期與執行緒相同,虛擬機器棧描述的是Java方法執行的記憶體模式:每個方法在執行的同時都會建立一個棧幀用於儲存區域性變量表,運算元棧,動態連結,方法出

Androidjava虛擬機器Dalvik虛擬機器的區別

   java虛擬機器和Dalvik虛擬機器的區別: java虛擬機器 Dalvik虛擬機器 java虛擬機器基於棧。 基於棧的機器必須使用指令來載入和操作棧上資料,所需指令更多更多 dalvik虛擬機器是基於暫存器的 java虛擬機器執行的是java位元組碼。(java類會被編譯成一個或多個位元

深入Java虛擬機器Java虛擬機器工作原理詳解

轉自:https://blog.csdn.net/bingduanlbd/article/details/8363734 一、類載入器 首先來看一下java程式的執行過程。               &nbs

《深度拆解Java虛擬機器Java虛擬機器是如何載入Java類的?

一、JVM的類載入 Java 虛擬機器中的類載入,從 class 位元組碼檔案到記憶體中的類,按先後順序需要經過載入、連結以及初始化三大步驟。其中,連結過程中同樣需要驗證;而記憶體中的類沒有經過初始化,同樣不能使用。那麼,是否所有的 Java 類都

深入理解AndroidView的繪製流程

本篇文章會從原始碼(基於Android 6.0)角度分析Android中View的繪製流程,側重於對整體流程的分析,對一些難以理解的點加以重點闡述,目的是把View繪製的整個流程把握好,而對於特定實現細節則可以日後再對相應原始碼進行研讀。 在進行實際的分析之前,我們先來看下面

深入理解AndroidXposed詳解

一、背景Xposed,大名鼎鼎得Xposed,是Android平臺上最負盛名的一個框架。在這個框架下,我們可以載入很多外掛App,這些外掛App可以直接或間接操縱系統層面的東西,比如操縱一些本來只對系統廠商才open的功能(實際上是因為Android系統很多API是不公開的,

深入理解系列JAVA泛型機制

泛型是指在宣告(類,方法,屬性)的時候採用一個“標誌符”來代替,而只有在呼叫的時候才傳入真正的型別,我們最常見的泛型例項就是前面講述的集合類,集合類在宣告的時候都是通過泛型方式來宣告的,只有在呼叫(例項化)時我們才確定傳入的是Integer亦或是Strin

深入理解系列JAVA資料結構(4)——Hashtable

1、Hashtable和HashMap,從儲存結構和實現來講基本上都是相同的, Hashtable繼承自Dictionary類,而HashMap繼承自AbstractMap類,但二者都實現了Map介面。 2、它和HashMap的最大的不同是它是

深入理解系列JAVA動態代理機制

代理的作用,就是生成代理物件使得真實物件的某些方法執行被代理物件攔截,從而在真實方法執行前、執行後新增額外的“動作”!動態代理則是指不需要修改原來的物件方法,在程式執行的過程中動態的生成代理物件,從而動態的生成這些“額外的”動作,主要從兩個方面來深入理解動

深入理解系列JAVA多執行緒(2)——synchronized同步原理

多執行緒中為了解決執行緒安全問題,一個重要的手段就是同步!所謂同步其實就是使得原本各個執行緒交叉執行(非同步),變成排隊執行(同步)。同步策略使得不同執行緒操作共享資料遵循“先來後到“,從而避免某個執行緒沒有處理完資料就被另一執行緒搶佔操作出現資料被覆蓋或

深入理解系列JAVA資料結構(2)——LinkedList

1、LinkedList 是一個繼承於AbstractSequentialList的雙向連結串列。它也可以被當作堆疊、佇列或雙端佇列進行操作。 2、LinkedList相對於ArrayList來說,是可以快速新增,刪除元素,ArrayList新增刪除

深入理解系列JAVA多型機制(過載/重寫)

多型(Polymorphism)按字面的意思就是“多種狀態”。在面嚮物件語言中,介面的多種不同的實現方式即為多型(來自百度百科)。所以,按照這個意思其實多型的“主題”是物件,但是實際在我們運用中我們常把“過載”和“重寫”稱之為“多型”其實這是不嚴謹的!過載

深入理解AndroidAOP

格式更加精美的PDF版請到:http://vdisk.weibo.com/s/z68f8l0xTgCLK 下載 一、閒談AOP 大家都知道OOP,即ObjectOriented Programming,面向物件程式設計。而本文要介紹的是AOP。AOP是Aspect Or

深入理解JVM(③)虛擬機器效能監控、故障處理工具

#前言 JDK的bin目錄中有一系列的小工具,除了java.exe、javac.exe這兩個編譯和執行Java程式外,還有打包、部署、簽名、除錯、監控、運維等各種場景都會用到這些小工具。 ![](https://img2020.cnblogs.com/blog/772743/202006/772743-202

深入理解JVM(③)虛擬機器的類載入時機

## 前言 Java虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別,這個過程被稱為虛擬機器的類載入機制。 ### 類載入的時機 一個型別從被載入到虛擬機器記憶體中開始,到解除安裝除記憶體為止,它的生命週期將會經歷==載入(L

深入理解JVM(③)虛擬機器的類載入過程

## 前言 上一篇我們介紹到一個類的生命週期大概分7個階段:載入、驗證、準備、解析、初始化、使用、解除安裝。並且也介紹了類的載入時機,下面我們將介紹一下虛擬機器中類的載入的全過程。**主要是類生命週期的,載入、驗證、準備、解析和初始化這五個階段所執行的具體動作。** ### 載入 類載入過程的第一個階段就是載

深入理解Java虛擬機器—JVM高階特性與實踐 周志明 著》第2章 Java記憶體區域與記憶體溢位異常

1、Java虛擬機器所管理的記憶體包括以下幾個執行時資料區域: 2、程式計數器:          1. 可以看作是當前執行緒所執行的位元組碼的行號指示器,是一塊較小的記憶體空間;  &nbs