編譯順序 編譯器 虛擬機 虛擬機
java源文件*
java
>字節碼*
class
>類裝載器
>執行引擎
一個
class文件只能包含一個類或接口
因此
java文件中定義了多少類
編譯時就會生成多少
class文件(內部類不算)
java程序可以選擇兩種方式訪問底層系統由程序員選擇 (
)
通過java程序調用javaapi調用本地方法
訪問底層系統
與平台無關
(
)
通過java程序直接調用本地方法
訪問底層系統與平台相關
本地方法即操作系統提供的方法
類裝載器 裝載java編譯器編譯好的字節碼*
class和java api的字節碼到方法區
java有兩種類裝載器
(
)
啟動類裝載器
系統唯一
屬於虛擬機的一部分
用特定語言編寫(與虛擬機體層語言相通)使用默認方式裝載類
主要用來裝載核心類庫
(
)
用戶自定義類裝載器
可有任意多個
用java編寫
屬於java應用程序的一部分
能被編譯成字節碼
並被虛擬機所裝載
一個裝載器裝載一個類及其該類所調用的一切類
使他們相互聯系
並形成一個命名空間(name space)
每一個類裝載器對應一個命名空間
即java中名字空間的原理
類裝載器成線形排列
自底向上
頂部為啟動類裝載器
除啟動類裝載器外
其他類裝載器都由用戶實例化
用來裝載不同的類
當要裝載一
個類時
底部的裝載器試圖將該類交給父裝載器裝載
而該父類又試圖交給他的父類裝載
一直向上
直到啟動類裝載器
若父類裝載器無法
裝載
則交給子類裝載器裝載
子類裝載能裝載的部分
將余下部分交給他的子類
直到底部
如
裝載器a
b
c
d
e
f
啟動
a
>b
>c
>d
>e
>f
>啟動
當有一個類fun需要被裝載時
他會一直上溯到頂部即啟動類裝載器
如果啟動類裝載器無法裝載fun則交給f裝載
f裝載能裝載的部分
將其
余部分交給e
然後一直這樣下去
如上所述
運行過程中每個類裝載器裝載的類形成一個運行時包
同一運行時包裡的類可以互相訪問
但不能訪問包外部的類
虛擬機的生命周期 每個java程序都有自己的虛擬機實例
隨著程序的產生和消亡而產生與消亡
java程序運行時的內存結構 程序空間分為方法區
堆
java棧
本地方法棧
(
)方法區存放裝載的類數據信息包括
基本信息
每個類的全限定名
每個類的直接超類的全限定名(可約束類型轉換)
該類是類還是接口
該類型的訪問修飾符
直接超接口的全限定名的有序列表
每個已裝載類的詳細信息
運行時常量池
存放該類型所用的一切常量(直接常量和對其他類型
字段
方法的符號引用)
它們以數組形式通過索引被訪問
是外部調用
與類聯系及類型對象化的橋梁
它是類文件(字節碼)常量池的運行時表示
(還有一種靜態常量池
在字節碼文件中)
字段信息
類中聲明的每一個字段的信息(名
類型
修飾符)
方法信息
類中聲明的每一個方法的信息(名
放回類型
參數類型
修飾符
方法的字節碼和異常表)
靜態變量
到類classloader的引用
即到該類的類裝載器的引用
到類class的引用
虛擬機為每一個被裝載的類型創建一個class實例
用來代表這個被裝載的類
(
)堆存放所有生成的對象及對象的實例變量
(
)java棧以幀的形似存放本地方法的調用狀態(包括方法調用的參數
局部變量
中間結果等)
每調用一個方法就將對應該方法的方法幀壓入
java棧
成為當前方法幀
當調用結束(返回)時
就彈出該幀
編譯器將原代碼編譯成字節碼(
class)時
就已經將各種類型的方法的局部變
量
操作數棧大小確定並放在字節碼中
隨著類一並裝載入方法區
當調用方法時
通過訪問方法區中的類的信息
得到局部變量以及操作數
棧的大小
java棧幀(即方法幀)由局部變量區
操作數棧
幀數據區組成
局部變量區為一個以字為單位的數組
每個數組元素對應一個局部變量的值
調用方法時
將方法的局部變量組成一個數組
通過索引來訪問
若為非靜態方法
則加入一個隱含的引用參數this
該參數指向調用這個方法的對象
而靜態方法則沒有this參數
因此
對象無法調用靜態
方法
操作數棧也是一個數組
但卻是通過棧操作來訪問
所謂操作數是那些被指令操作的數據
當需要對參數操作時如a=b+c
就將即將被操作的參數壓棧
如將b和c壓棧
然後由操作指令將他們彈出
並執行操作
此處由iadd指令將b和c彈出並相加
然後壓入操作數棧(一系列均由iadd執行)然後由i_storex指令將結果彈出
存到索引x指向的局部變量區數組內(此處索引x指向局部變量a)
虛擬機將操作數棧作為工作區
幀數據區處理常量池解析
異常處理等
(
)本地方法棧
與調用的本地方法的語言相關
如調用的是一個c語言方法則為一個c棧
本地方法可以回調java方法
若有java方法調用本地方法
虛擬機就運行這個本地方法
在虛擬機看來運行這個本地方法就是執行這個java方法
如果本地方法拋出異常
虛擬機就認為是這個java方法拋出異常
(
)執行程序時
通過對象的引用在方法區中查找裝載的類
若還沒有裝載
則查找字節碼(類名
class)
並將其裝載入方法區
在執行過程中
虛擬機會將對象的符號引用(即對象名)替換為直接的指針
以提高訪問速度
(
)因此
大體可以表述為
方法區
存儲類包括接口的各種信息
字節碼裝載到此處
java棧
存儲被調用的方法的各種信息
只有調用該方法時
才會將該方法幀壓入java棧
堆
存儲對象的信息
包括對象的實例變量
但不包括對象的方法
只有調用對象的方法時
才將方法幀壓入java棧中
java數據類型 數值類型
浮點類型
float double
整數類型
byte
short
int
long
char(int和char可以互換)
引用類型
類類型
接口類型
數組類型
java的引用類型 引用與指針
引用代表被引用的對象
它只是引用對象的代表
並不占用內存
也不能修改
如引用變量沒有引用對象
則該引用變量=null
指針存放對象的地址
它是一個變量
可以被修改
和其他變量一樣
占用內存
方法區 所有線程共享方法區
但為滿足線程安全
方法區中每一個類必須被設定為臨界資源
即同一時刻某一個類只能被一個線程訪問
類標識 由於一個程序可以多次裝載同一個類且該類可以存在於不同的名字空間中(即可由不同的裝載器裝載)
因此必須將裝載該類的裝載器的標識加上
才能唯一標識一個類
對象 對象實例變量存儲在堆中
對象符號引用則在常量池
方法屬性表等可能出現的地方
通過對象的引用可以訪問對象的實例數據和創建該對象
的類的數據
對象的引用指向堆中的對象
實例結構有兩種
見書本
頁
當調用對象的方法時
需要進行動態綁定
即
不能根據對象來確定需要調用的方法
而是根據對象的類數據來確定需要調用的方法
此時
也需要通過對象的引用來訪問類數據
動態綁定就是在運行時才綁定
而不是在編譯時綁定
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26169.html