- 首頁(yè)|
- 網(wǎng)校|
- 焚題庫(kù)|
- APP |
-
微信公眾號(hào)
1 Java技術(shù)與Java虛擬機(jī)
說(shuō)起Java,人們首先想到的是Java編程語(yǔ)言,然而事實(shí)上,Java是一種技術(shù),它由四方面組成: Java編程語(yǔ)言、Java類文件格式、Java虛擬機(jī)和Java應(yīng)用程序接口(Java API)。它們的關(guān)系如下圖所示:
圖1 Java四個(gè)方面的關(guān)系
運(yùn)行期環(huán)境代表著Java平臺(tái),開(kāi)發(fā)人員編寫(xiě)Java代碼(.java文件),然后將之編譯成字節(jié)碼(.class 文件)。最后字節(jié)碼被裝入內(nèi)存,一旦字節(jié)碼進(jìn)入虛擬機(jī),它就會(huì)被解釋器解釋執(zhí)行,或者是被即時(shí)代碼發(fā)生器有選擇的轉(zhuǎn)換成機(jī)器碼執(zhí)行。從上圖也可以看出 Java平臺(tái)由Java虛擬機(jī)和Java應(yīng)用程序接口搭建,Java語(yǔ)言則是進(jìn)入這個(gè)平臺(tái)的通道,用Java語(yǔ)言編寫(xiě)并編譯的程序可以運(yùn)行在這個(gè)平臺(tái)上。 這個(gè)平臺(tái)的結(jié)構(gòu)如下圖所示:
在Java平臺(tái)的結(jié)構(gòu)中, 可以看出,Java虛擬機(jī)(JVM) 處在核 心的位置,是程序與底層操作系統(tǒng)和硬件無(wú)關(guān)的關(guān)鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統(tǒng), 其中依賴于平臺(tái)的部分稱為適配器;JVM 通過(guò)移植接口在具體的平臺(tái)和操作系統(tǒng)上實(shí)現(xiàn);在JVM 的上方是Java的基本類庫(kù)和擴(kuò)展類庫(kù)以及它們的API, 利用Java API編寫(xiě)的應(yīng)用程序(application) 和小程序(Java applet) 可以在任何Java平臺(tái)上運(yùn)行而無(wú)需考慮底層平臺(tái), 就是因?yàn)橛蠮ava虛擬機(jī)(JVM)實(shí)現(xiàn)了程序與操作系統(tǒng)的分離,從而實(shí)現(xiàn)了Java 的平臺(tái)無(wú)關(guān)性。
那么到底什么是Java虛擬機(jī)(JVM)呢?通常我們談?wù)揓VM時(shí),我們的意思可能是:
對(duì)JVM規(guī)范的的比較抽象的說(shuō)明;
對(duì)JVM的具體實(shí)現(xiàn);
在程序運(yùn)行期間所生成的一個(gè)JVM實(shí)例。
對(duì)JVM規(guī)范的的抽象說(shuō)明是一些概念的集合,它們已經(jīng)在書(shū)《The Java Virtual Machine Specification》(《Java虛擬機(jī)規(guī)范》)中被詳細(xì)地描述了;對(duì)JVM的具體實(shí)現(xiàn)要么是軟件,要么是軟件和硬件的組合,它已經(jīng)被許多生產(chǎn)廠 商所實(shí)現(xiàn),并存在于多種平臺(tái)之上;運(yùn)行Java程序的任務(wù)由JVM的運(yùn)行期實(shí)例單個(gè)承擔(dān)。在本文中我們所討論的Java虛擬機(jī)(JVM)主要針對(duì)第三種情 況而言。它可以被看成一個(gè)想象中的機(jī)器,在實(shí)際的計(jì)算機(jī)上通過(guò)軟件模擬來(lái)實(shí)現(xiàn),有自己想象中的硬件,如處理器、堆棧、寄存器等,還有自己相應(yīng)的指令系統(tǒng)。
JVM在它的生存周期中有一個(gè)明確的任務(wù),那就是運(yùn)行Java程序,因此當(dāng)Java程序啟動(dòng)的時(shí)候,就產(chǎn)生JVM的一個(gè)實(shí)例;當(dāng)程序運(yùn)行結(jié)束的時(shí)候,該實(shí)例也跟著消失了。下面我們從JVM的體系結(jié)構(gòu)和它的運(yùn)行過(guò)程這兩個(gè)方面來(lái)對(duì)它進(jìn)行比較深入的研究。
2 Java虛擬機(jī)的體系結(jié)構(gòu)
剛才已經(jīng)提到,JVM可以由不同的廠商來(lái)實(shí)現(xiàn)。由于廠商的不同必 然導(dǎo)致JVM在實(shí)現(xiàn)上的一些不同,然而JVM還是可以實(shí)現(xiàn)跨平臺(tái)的特性,這就要?dú)w功于設(shè)計(jì)JVM時(shí)的體系結(jié)構(gòu)了。
我們知道,一個(gè)JVM實(shí)例的行為不光是它自己的事,還涉及到它的子系統(tǒng)、存儲(chǔ)區(qū)域、數(shù)據(jù)類型和指令這些部分,它們描 述了JVM的一個(gè)抽象的內(nèi)部體系結(jié)構(gòu),其目的不光規(guī)定實(shí)現(xiàn)JVM時(shí)它內(nèi)部的體系結(jié)構(gòu),更重要的是提供了一種方式,用于嚴(yán)格定義實(shí)現(xiàn)時(shí)的外部行為。每個(gè) JVM都有兩種機(jī)制,一個(gè)是裝載具有合適名稱的類(類或是接口),叫做類裝載子系統(tǒng);另外的一個(gè)負(fù)責(zé)執(zhí)行包含在已裝載的類或接口中的指令,叫做運(yùn)行引擎。 每個(gè)JVM又包括方法區(qū)、堆、Java棧、程序計(jì)數(shù)器和本地方法棧這五個(gè)部分,這幾個(gè)部分和類裝載機(jī)制與運(yùn)行引擎機(jī)制一起組成的體系結(jié)構(gòu)圖為:
圖3 JVM的體系結(jié)構(gòu)
JVM的每個(gè)實(shí)例都有一個(gè)它自己的方法域和一個(gè)堆,運(yùn)行于JVM內(nèi)的所有的線程都共享這些區(qū)域;當(dāng)虛擬機(jī)裝載類文件 的時(shí)候,它解析其中的二進(jìn)制數(shù)據(jù)所包含的類信息,并把它們放到方法域中;當(dāng)程序運(yùn)行的時(shí)候,JVM把程序初始化的所有對(duì)象置于堆上;而每個(gè)線程創(chuàng)建的時(shí) 候,都會(huì)擁有自己的程序計(jì)數(shù)器和Java棧,其中程序計(jì)數(shù)器中的值指向下一條即將被執(zhí)行的指令,線程的Java棧則存儲(chǔ)為該線程調(diào)用Java方法的狀態(tài); 本地方法調(diào)用的狀態(tài)被存儲(chǔ)在本地方法棧,該方法棧依賴于具體的實(shí)現(xiàn)。
下面分別對(duì)這幾個(gè)部分進(jìn)行說(shuō)明。
執(zhí)行引擎處于JVM的核 心位置,在Java虛擬機(jī)規(guī)范中,它的行為是由指令集所決定的。盡管對(duì)于每條指令,規(guī)范很詳 細(xì)地說(shuō)明了當(dāng)JVM執(zhí)行字節(jié)碼遇到指令時(shí),它的實(shí)現(xiàn)應(yīng)該做什么,但對(duì)于怎么做卻言之甚少。Java虛擬機(jī)支持大約248個(gè)字節(jié)碼。每個(gè)字節(jié)碼執(zhí)行一種基本 的CPU運(yùn)算,例如,把一個(gè)整數(shù)加到寄存器,子程序轉(zhuǎn)移等。Java指令集相當(dāng)于Java程序的匯編語(yǔ)言。
Java指令集中的指令包含一個(gè)單字節(jié)的操作符,用于指定要執(zhí)行的操作,還有0個(gè)或多個(gè)操作數(shù),提供操作所需的參數(shù)或數(shù)據(jù)。許多指令沒(méi)有操作數(shù),僅由一個(gè)單字節(jié)的操作符構(gòu)成。
虛擬機(jī)的內(nèi)層循環(huán)的執(zhí)行過(guò)程如下: do{ 取一個(gè)操作符字節(jié); 根據(jù)操作符的值執(zhí)行一個(gè)動(dòng)作; }while(程序未結(jié)束)
由于指令系統(tǒng)的簡(jiǎn)單性,使得虛擬機(jī)執(zhí)行的過(guò)程十分簡(jiǎn)單,從而有利于提高執(zhí)行的效率。指令中操作數(shù)的數(shù)量和大小是由操作符決定的。如果操作數(shù)比一個(gè)字節(jié)大,那么它存儲(chǔ)的順序是高位字節(jié)優(yōu)先。例如,一個(gè)16位的參數(shù)存放時(shí)占用兩個(gè)字節(jié),其值為:
第 一個(gè)字節(jié)*256+第二個(gè)字節(jié)字節(jié)碼。
指令流一般只是字節(jié)對(duì)齊的。指令tableswitch和lookup是例外,在這兩條指令內(nèi)部要求強(qiáng)制的4字節(jié)邊界對(duì)齊。
對(duì)于本地方法接口,實(shí)現(xiàn)JVM并不要求一定要有它的支持,甚至可以完全沒(méi)有。Sun公司實(shí)現(xiàn)Java本地接口 (JNI)是出于可移植性的考慮,當(dāng)然我們也可以設(shè)計(jì)出其它的本地接口來(lái)代替Sun公司的JNI。但是這些設(shè)計(jì)與實(shí)現(xiàn)是比較復(fù)雜的事情,需要確保垃圾回收 器不會(huì)將那些正在被本地方法調(diào)用的對(duì)象釋放掉。
Java的堆是一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),類的實(shí)例(對(duì)象)從中分配空間,它的管理是由垃圾回收來(lái)負(fù)責(zé)的:不給程序員顯式釋放對(duì)象的能力。Java不規(guī)定具體使用的垃圾回收算法,可以根據(jù)系統(tǒng)的需求使用各種各樣的算法。
Java方法區(qū)與傳統(tǒng)語(yǔ)言中的編譯后代碼或是Unix進(jìn)程中的正文段類似。它保存方法代碼(編譯后的java代碼) 和符號(hào)表。在當(dāng)前的Java實(shí)現(xiàn)中,方法代碼不包括在垃圾回收堆中,但計(jì)劃在將來(lái)的版本中實(shí)現(xiàn)。每個(gè)類文件包含了一個(gè)Java類或一個(gè)Java界面的編譯 后的代碼?梢哉f(shuō)類文件是Java語(yǔ)言的執(zhí)行代碼文件。為了保證類文件的平臺(tái)無(wú)關(guān)性,Java虛擬機(jī)規(guī)范中對(duì)類文件的格式也作了詳細(xì)的說(shuō)明。其具體細(xì)節(jié)請(qǐng) 參考Sun公司的Java虛擬機(jī)規(guī)范。
Java虛擬機(jī)的寄存器用于保存機(jī)器的運(yùn)行狀態(tài),與微處理器中的某些專用寄存器類似。Java虛擬機(jī)的寄存器有四種:
pc: Java程序計(jì)數(shù)器;
optop: 指向操作數(shù)棧頂端的指針;
frame: 指向當(dāng)前執(zhí)行方法的執(zhí)行環(huán)境的指針;。
vars: 指向當(dāng)前執(zhí)行方法的局部變量區(qū)第 一個(gè)變量的指針。
在上述體系結(jié)構(gòu)圖中,我們所說(shuō)的是第 一種,即程序計(jì)數(shù)器,每個(gè)線程一旦被創(chuàng)建就擁有了自己的程序計(jì)數(shù)器。當(dāng)線程執(zhí)行Java方法的時(shí)候,它包含該線程正在被執(zhí)行的指令的地址。但是若線程執(zhí)行的是一個(gè)本地的方法,那么程序計(jì)數(shù)器的值就不會(huì)被定義。
Java虛擬機(jī)的棧有三個(gè)區(qū)域:局部變量區(qū)、運(yùn)行環(huán)境區(qū)、操作數(shù)區(qū)。
局部變量區(qū)
每個(gè)Java方法使用一個(gè)固定大小的局部變量集。它們按照與vars寄存器的字偏移量來(lái)尋址。局部變量都是32位 的。長(zhǎng)整數(shù)和雙精度浮點(diǎn)數(shù)占據(jù)了兩個(gè)局部變量的空間,卻按照第 一個(gè)局部變量的索引來(lái)尋址。(例如,一個(gè)具有索引n的局部變量,如果是一個(gè)雙精度浮點(diǎn)數(shù),那 么它實(shí)際占據(jù)了索引n和n+1所代表的存儲(chǔ)空間)虛擬機(jī)規(guī)范并不要求在局部變量中的64位的值是64位對(duì)齊的。虛擬機(jī)提供了把局部變量中的值裝載到操作數(shù) 棧的指令,也提供了把操作數(shù)棧中的值寫(xiě)入局部變量的指令。
運(yùn)行環(huán)境區(qū)
在運(yùn)行環(huán)境中包含的信息用于動(dòng)態(tài)鏈接,正常的方法返回以及異常捕捉。
填寫(xiě)下面表單即可預(yù)約申請(qǐng)免費(fèi)試聽(tīng)java課程!害怕學(xué)不會(huì)?助教陪讀,隨時(shí)解惑!擔(dān)心就業(yè)?一地學(xué)習(xí),可全國(guó)推薦就業(yè)!
動(dòng)態(tài)鏈接
運(yùn)行環(huán)境包括對(duì)指向當(dāng)前類和當(dāng)前方法的解釋器符號(hào)表的指針,用于支持方法代碼的動(dòng)態(tài)鏈接。方法的class文件代碼 在引用要調(diào)用的方法和要訪問(wèn)的變量時(shí)使用符號(hào)。動(dòng)態(tài)鏈接把符號(hào)形式的方法調(diào)用翻譯成實(shí)際方法調(diào)用,裝載必要的類以解釋還沒(méi)有定義的符號(hào),并把變量訪問(wèn)翻譯 成與這些變量運(yùn)行時(shí)的存儲(chǔ)結(jié)構(gòu)相應(yīng)的偏移地址。動(dòng)態(tài)鏈接方法和變量使得方法中使用的其它類的變化不會(huì)影響到本程序的代碼。
正常的方法返回
如果當(dāng)前方法正常地結(jié)束了,在執(zhí)行了一條具有正確類型的返回指令時(shí),調(diào)用的方法會(huì)得到一個(gè)返回值。執(zhí)行環(huán)境在正常返回的情況下用于恢復(fù)調(diào)用者的寄存器,并把調(diào)用者的程序計(jì)數(shù)器增加一個(gè)恰當(dāng)?shù)臄?shù)值,以跳過(guò)已執(zhí)行過(guò)的方法調(diào)用指令,然后在調(diào)用者的執(zhí)行環(huán)境中繼續(xù)執(zhí)行下去。
異常捕捉
異常情況在Java中被稱作Error(錯(cuò)誤)或Exception(異常),是Throwable類的子類,在程序中的原因是:①動(dòng)態(tài)鏈接錯(cuò),如無(wú)法找到所需的class文件。②運(yùn)行時(shí)錯(cuò),如對(duì)一個(gè)空指針的引用。程序使用了throw語(yǔ)句。
當(dāng)異常發(fā)生時(shí),Java虛擬機(jī)采取如下措施:
檢查與當(dāng)前方法相聯(lián)系的catch子句表。每個(gè)catch子句包含其有效指令范圍,能夠處理的異常類型,以及處理異常的代碼塊地址。
與 異常相匹配的catch子句應(yīng)該符合下面的條件:造成異常的指令在其指令范圍之內(nèi),發(fā)生的異常類型是其能處理的異常類型的子類型。如果找到了匹配的 catch子句,那么系統(tǒng)轉(zhuǎn)移到指定的異常處理塊處執(zhí)行;如果沒(méi)有找到異常處理塊,重復(fù)尋找匹配的catch子句的過(guò)程,直到當(dāng)前方法的所有嵌套的 catch子句都被檢查過(guò)。
由于虛擬機(jī)從第 一個(gè)匹配的catch子句處繼續(xù)執(zhí)行,所以catch子句表中的順序是很重 要的。因?yàn)镴ava代碼是結(jié)構(gòu)化的,因此總可以把某個(gè)方法的所有的異常處理器都按序排列到一個(gè)表中,對(duì)任意可能的程序計(jì)數(shù)器的值,都可以用線性的順序找到 合適的異常處理塊,以處理在該程序計(jì)數(shù)器值下發(fā)生的異常情況。
如果找不到匹配的catch子句,那么當(dāng)前方法得到一 個(gè)"未截獲異常"的結(jié)果并返回到當(dāng)前方法的調(diào)用者,好像異常剛剛在其調(diào)用者中發(fā)生一樣。如果在調(diào)用者中仍然沒(méi)有找到相應(yīng)的異常處理塊,那么這種錯(cuò)誤將被傳 播下去。如果錯(cuò)誤被傳播到最頂層,那么系統(tǒng)將調(diào)用一個(gè)缺省的異常處理塊。
操作數(shù)棧區(qū)
機(jī)器指令只從操作數(shù)棧中取操作數(shù),對(duì)它們進(jìn)行操作,并把結(jié)果返回到棧中。選擇棧結(jié)構(gòu)的原因是:在只有少量寄存器或非 通用寄存器的機(jī)器(如Intel486)上,也能夠高 效地模擬虛擬機(jī)的行為。操作數(shù)棧是32位的。它用于給方法傳遞參數(shù),并從方法接收結(jié)果,也用于支持操 作的參數(shù),并保存操作的結(jié)果。例如,iadd指令將兩個(gè)整數(shù)相加。相加的兩個(gè)整數(shù)應(yīng)該是操作數(shù)棧頂?shù)膬蓚(gè)字。這兩個(gè)字是由先前的指令壓進(jìn)堆棧的。這兩個(gè)整 數(shù)將從堆棧彈出、相加,并把結(jié)果壓回到操作數(shù)棧中。
每個(gè)原始數(shù)據(jù)類型都有專門(mén)的指令對(duì)它們進(jìn)行必須的操作。每個(gè)操作數(shù)在棧中需要一個(gè)存儲(chǔ)位置,除了long和 double型,它們需要兩個(gè)位置。操作數(shù)只能被適用于其類型的操作符所操作。例如,壓入兩個(gè)int類型的數(shù),如果把它們當(dāng)作是一個(gè)long類型的數(shù)則是 非法的。在Sun的虛擬機(jī)實(shí)現(xiàn)中,這個(gè)限制由字節(jié)碼驗(yàn)證器強(qiáng)制實(shí)行。但是,有少數(shù)操作(操作符dupe和swap),用于對(duì)運(yùn)行時(shí)數(shù)據(jù)區(qū)進(jìn)行操作時(shí)是不考 慮類型的。
本地方法棧,當(dāng)一個(gè)線程調(diào)用本地方法時(shí),它就不再受到虛擬機(jī)關(guān)于結(jié)構(gòu)和安全限制方面的約束,它既可以訪問(wèn)虛擬機(jī)的運(yùn) 行期數(shù)據(jù)區(qū),也可以使用本地處理器以及任何類型的棧。例如,本地棧是一個(gè)C語(yǔ)言的棧,那么當(dāng)C程序調(diào)用C函數(shù)時(shí),函數(shù)的參數(shù)以某種順序被壓入棧,結(jié)果則返 回給調(diào)用函數(shù)。在實(shí)現(xiàn)Java虛擬機(jī)時(shí),本地方法接口使用的是C語(yǔ)言的模型棧,那么它的本地方法棧的調(diào)度與使用則完全與C語(yǔ)言的棧相同。
3 Java虛擬機(jī)的運(yùn)行過(guò)程
上面對(duì)虛擬機(jī)的各個(gè)部分進(jìn)行了比較詳細(xì)的說(shuō)明,下面通過(guò)一個(gè)具體的例子來(lái)分析它的運(yùn)行過(guò)程。
虛擬機(jī)通過(guò)調(diào)用某個(gè)指定類的方法main啟動(dòng),傳遞給main一個(gè)字符串?dāng)?shù)組參數(shù),使指定的類被裝載,同時(shí)鏈接該類所使用的其它的類型,并且初始化它們。例如對(duì)于程序:
class HelloApp { public static void main(String[] args) { System.out.println("Hello World!"); for (int i = 0; i < args.length; i++ ) { System.out.println(args[i]); } }}
編譯后在命令行模式下鍵入: java HelloApp run virtual machine
將通過(guò)調(diào)用HelloApp的方法main來(lái)啟動(dòng)java虛擬機(jī),傳遞給main一個(gè)包含三個(gè)字符串"run"、"virtual"、"machine"的數(shù)組,F(xiàn)在我們略述虛擬機(jī)在執(zhí)行HelloApp時(shí)可能采取的步驟。
開(kāi)始試圖執(zhí)行類HelloApp的main方法,發(fā)現(xiàn)該類并沒(méi)有被裝載,也就是說(shuō)虛擬機(jī)當(dāng)前不包含該類的二進(jìn)制代 表,于是虛擬機(jī)使用ClassLoader試圖尋找這樣的二進(jìn)制代表。如果這個(gè)進(jìn)程失敗,則拋出一個(gè)異常。類被裝載后同時(shí)在main方法被調(diào)用之前,必須 對(duì)類HelloApp與其它類型進(jìn)行鏈接然后初始化。鏈接包含三個(gè)階段:檢驗(yàn),準(zhǔn)備和解析。檢驗(yàn)檢查被裝載的主類的符號(hào)和語(yǔ)義,準(zhǔn)備則創(chuàng)建類或接口的靜態(tài) 域以及把這些域初始化為標(biāo)準(zhǔn)的默認(rèn)值,解析負(fù)責(zé)檢查主類對(duì)其它類或接口的符號(hào)引用,在這一步它是可選的。類的初始化是對(duì)類中聲明的靜態(tài)初始化函數(shù)和靜態(tài)域 的初始化構(gòu)造方法的執(zhí)行。一個(gè)類在初始化之前它的父類必須被初始化。整個(gè)過(guò)程如下:
圖4:虛擬機(jī)的運(yùn)行過(guò)程
4 結(jié)束語(yǔ)
本文通過(guò)對(duì)JVM的體系結(jié)構(gòu)的深入研究以及一個(gè)Java程序執(zhí)行時(shí)虛擬機(jī)的運(yùn)行過(guò)程的詳細(xì)分析,意在剖析清楚Java虛擬機(jī)的機(jī)理。
下一篇: 沒(méi)有了
初級(jí)會(huì)計(jì)職稱中級(jí)會(huì)計(jì)職稱經(jīng)濟(jì)師注冊(cè)會(huì)計(jì)師證券從業(yè)銀行從業(yè)會(huì)計(jì)實(shí)操統(tǒng)計(jì)師審計(jì)師高級(jí)會(huì)計(jì)師基金從業(yè)資格稅務(wù)師資產(chǎn)評(píng)估師國(guó)際內(nèi)審師ACCA/CAT價(jià)格鑒證師統(tǒng)計(jì)資格從業(yè)
一級(jí)建造師二級(jí)建造師消防工程師造價(jià)工程師土建職稱房地產(chǎn)經(jīng)紀(jì)人公路檢測(cè)工程師建筑八大員注冊(cè)建筑師二級(jí)造價(jià)師監(jiān)理工程師咨詢工程師房地產(chǎn)估價(jià)師 城鄉(xiāng)規(guī)劃師結(jié)構(gòu)工程師巖土工程師安全工程師設(shè)備監(jiān)理師環(huán)境影響評(píng)價(jià)土地登記代理公路造價(jià)師公路監(jiān)理師化工工程師暖通工程師給排水工程師計(jì)量工程師
人力資源考試教師資格考試出版專業(yè)資格健康管理師導(dǎo)游考試社會(huì)工作者司法考試職稱計(jì)算機(jī)營(yíng)養(yǎng)師心理咨詢師育嬰師事業(yè)單位教師招聘公務(wù)員公選考試招警考試選調(diào)生村官
執(zhí)業(yè)藥師執(zhí)業(yè)醫(yī)師衛(wèi)生資格考試衛(wèi)生高級(jí)職稱護(hù)士資格證初級(jí)護(hù)師主管護(hù)師住院醫(yī)師臨床執(zhí)業(yè)醫(yī)師臨床助理醫(yī)師中醫(yī)執(zhí)業(yè)醫(yī)師中醫(yī)助理醫(yī)師中西醫(yī)醫(yī)師中西醫(yī)助理口腔執(zhí)業(yè)醫(yī)師口腔助理醫(yī)師公共衛(wèi)生醫(yī)師公衛(wèi)助理醫(yī)師實(shí)踐技能內(nèi)科主治醫(yī)師外科主治醫(yī)師中醫(yī)內(nèi)科主治兒科主治醫(yī)師婦產(chǎn)科醫(yī)師西藥士/師中藥士/師臨床檢驗(yàn)技師臨床醫(yī)學(xué)理論中醫(yī)理論