簡(jiǎn)述Java代碼從編寫(xiě)到運(yùn)行的全過(guò)程
- 編寫(xiě)代碼: 將需求通過(guò)代碼實(shí)現(xiàn)
- 編譯成字節(jié)碼文件:將編碼后的源程序編譯成字節(jié)碼文件 .class
- 類(lèi)裝載(classloader): 為運(yùn)行程序?qū)ふ一蜓b載所需要的類(lèi)
- 字節(jié)碼校驗(yàn)(bytecode verifier): 校驗(yàn)class的代碼,保證安全性,比如對(duì)象類(lèi)型,對(duì)象訪問(wèn)權(quán)限
- 解釋(interprter):機(jī)器不認(rèn)識(shí)字節(jié)碼文件,需要被解釋器解釋后才能運(yùn)行
- 運(yùn)行: 最后代碼可以在運(yùn)行環(huán)境中進(jìn)行運(yùn)行
簡(jiǎn)述虛擬機(jī)的工作機(jī)制
同 【簡(jiǎn)述Java代碼從運(yùn)行到運(yùn)行的全過(guò)程】
簡(jiǎn)述回收機(jī)制
垃圾回收是指JVM通過(guò)一些垃圾回收算法回收分配出去且未被使用的內(nèi)存空間,提高程序運(yùn)行效率,防止出現(xiàn)內(nèi)存泄露。由于回收內(nèi)存空間需要耗費(fèi)時(shí)間,頻繁的進(jìn)行垃圾回收會(huì)影響程序的運(yùn)行效率,因此當(dāng)出現(xiàn)未被引用的對(duì)象,JVM不會(huì)立即進(jìn)行回收,而是選擇在合適的時(shí)候進(jìn)行回收。所以在程序中使用system.gc()不會(huì)立馬進(jìn)行垃圾回收,而是通知JVM需要進(jìn)行垃圾回收
簡(jiǎn)述java安全機(jī)制
- 類(lèi)裝載器結(jié)構(gòu)(class loader): 裝載和尋找程序執(zhí)行所需要的類(lèi)
- class文件檢查器(the class file verifier): 虛擬機(jī)校驗(yàn)裝載的字節(jié)碼文件的完整性,通過(guò)四趟進(jìn)行校驗(yàn)
第一趟:檢查文件結(jié)構(gòu),比如檢查文件是否符合JavaClass文件的節(jié)本結(jié)構(gòu)
第二趟:類(lèi)型數(shù)據(jù)的語(yǔ)義檢查,例如檢查final類(lèi)有沒(méi)有被子化等
第三趟:字節(jié)碼驗(yàn)證,確保操作數(shù)??偸前_的數(shù)值以及正確的類(lèi)型。
第四趟:符號(hào)引用的驗(yàn)證,由于Java程序是動(dòng)態(tài)鏈接的,所以Class文件檢查器在進(jìn)行第四次掃描中,必須檢查相互引用類(lèi)之間的兼容性。 - 內(nèi)置于JVM的一些安全特性:
a) 類(lèi)型安全的引用轉(zhuǎn)換
b) 自動(dòng)垃圾回收機(jī)制
c) 空引用檢查
d) 結(jié)構(gòu)化的內(nèi)存訪問(wèn) - Java管理器以及java api
簡(jiǎn)述java面向?qū)ο蟮娜筇匦?/h4>
- 封裝: 將屬性私有化只有類(lèi)內(nèi)部才能使用,提供對(duì)外使用的公有方法,就像常見(jiàn)的java bean,屬性都是priavte,set和get方法都是共有的。
為什么不直接將類(lèi)的屬性設(shè)置為public供外部使用,因?yàn)橹苯邮褂玫脑?huà),無(wú)法對(duì)屬性進(jìn)行相應(yīng)的處理再獲取,或者有些共有屬性只讀,不能修改,就不能直接將屬性設(shè)置為公有供外部使用。
- 繼承: 子類(lèi)繼承父類(lèi)的方法和屬性,并且可以重寫(xiě)父類(lèi)方法或者可以擴(kuò)展新方法。java是單繼承語(yǔ)言,就是一個(gè)子類(lèi),只能繼承一個(gè)父類(lèi)。java的繼承屬提高了java的程序復(fù)用性和擴(kuò)展性
- 多態(tài): 指java不同類(lèi)的對(duì)象可以對(duì)同一函數(shù)調(diào)用進(jìn)行響應(yīng),也就是函數(shù)調(diào)用可以根據(jù)發(fā)送對(duì)象的不同而采用不同的行為方式。java多態(tài)分為運(yùn)行時(shí)多態(tài)和編譯時(shí)多態(tài),編譯時(shí)多態(tài)指方法的重載,即在編譯時(shí)就可以確定使用哪個(gè)方法,運(yùn)行時(shí)多態(tài)是指Java在運(yùn)行時(shí)個(gè)根據(jù)調(diào)用方法的實(shí)例類(lèi)型來(lái)決定調(diào)用哪個(gè)方法。所以多態(tài)是指在繼承的基礎(chǔ)上,對(duì)父類(lèi)的引用可以指向子類(lèi)對(duì)象,調(diào)用子類(lèi)重寫(xiě)的方法,就是子類(lèi)向上轉(zhuǎn)型成父類(lèi),但是子類(lèi)特有的擴(kuò)展方法無(wú)法使用,可以通過(guò)強(qiáng)制類(lèi)型轉(zhuǎn)換實(shí)現(xiàn)調(diào)用特有方法
多態(tài)的例子
方法的按值傳遞和按引用傳遞
- 按值傳遞:方法的形參類(lèi)型不是引用類(lèi)型,則是按值傳遞,那么調(diào)用該方法時(shí),形參將實(shí)參拷貝一份進(jìn)行運(yùn)算,不會(huì)改變實(shí)參的值。
- 按引用傳遞:方法的形參類(lèi)型為引用類(lèi)型,則是按引用傳遞,那么調(diào)用該方法時(shí),傳遞的是實(shí)參的地址,形參的運(yùn)算會(huì)改變實(shí)參的值。
equals和==的區(qū)別
- equals: 對(duì)于引用類(lèi)型,比較引用類(lèi)型是否引用統(tǒng)一實(shí)例,對(duì)于一些包裝類(lèi)File,String,Date等,equals比較的都是類(lèi)型以及值,而不是判斷是否引用同一實(shí)例。
- == : 符號(hào)兩邊的數(shù)據(jù)類(lèi)型是否一致(可自動(dòng)轉(zhuǎn)換的數(shù)據(jù)類(lèi)型除外),對(duì)于引用類(lèi)型,就是判斷是否指向同一塊內(nèi)存地址
Java String為什么被設(shè)計(jì)成不可變的?
- 字符串常量池的需要:因?yàn)樵趈ava方法區(qū)有一塊字符串常量池,當(dāng)創(chuàng)建一個(gè)String對(duì)象時(shí),如果常量池中存儲(chǔ)著這個(gè)對(duì)象,直接引用這個(gè)對(duì)象,而不是新建一個(gè)對(duì)象。所以如果String對(duì)象可變,則會(huì)對(duì)引用它的實(shí)例造成影響
- 安全性:因?yàn)槎嗑€程中,可以對(duì)統(tǒng)一資源進(jìn)行讀寫(xiě),String被設(shè)計(jì)為不可變的,則只讀,不會(huì)引起安全隱患
- hashCode緩存的需要:因?yàn)橐恍?shù)據(jù)結(jié)構(gòu)中會(huì)緩存hashCode,這樣保證了不用每次都去計(jì)算hasCode,提高了效率
String,StringBuilder 和 StringBuffer的區(qū)別?
- String: 對(duì)象不可變,通過(guò)final修飾類(lèi)和value保證字符串對(duì)象不可變,每次操作字符串都會(huì)生成新的字符串對(duì)象,如果字符串常量池存在,則會(huì)引用已存在的字符串對(duì)象。
- StringBuffer: 字符串對(duì)象可變,對(duì)字符串的操作不會(huì)生成新的對(duì)象,因此效率比String操作相對(duì)較高。由于很多方法添加了synchronized修飾,所以是線程安全的
- StringBuilder: 字符串對(duì)象可變,原理同StringBuffer都繼承了AbstractStringBuiledr,通過(guò)字符串緩沖池管理字符串,但是沒(méi)有synchronized修飾符,所以時(shí)現(xiàn)場(chǎng)不安全的,但是效率比StringBuffer高
- 效率: StringBuilder > StringBuffer > String
線程安全: String,StringBuffer是線程安全的,StringBuilder是線程不安全的
為什么不直接將類(lèi)的屬性設(shè)置為public供外部使用,因?yàn)橹苯邮褂玫脑?huà),無(wú)法對(duì)屬性進(jìn)行相應(yīng)的處理再獲取,或者有些共有屬性只讀,不能修改,就不能直接將屬性設(shè)置為公有供外部使用。
多態(tài)的例子
線程安全: String,StringBuffer是線程安全的,StringBuilder是線程不安全的
Java Serializable接口介紹
- Serializable接口內(nèi)部沒(méi)有定義屬性和方法,主要是標(biāo)識(shí)此接口的實(shí)現(xiàn)類(lèi)可以被序列化和反序列化
深入了解接口和抽象類(lèi)
- 抽象類(lèi):用abstract修飾的類(lèi),含有不提供具體實(shí)現(xiàn)的抽象方法,抽象類(lèi)不能被實(shí)例化,需要由子類(lèi)繼承抽象類(lèi)實(shí)現(xiàn)父類(lèi)的抽象方法。
- 接口:特殊的抽象類(lèi),該類(lèi)中包含常量和抽象方法,子類(lèi)可以實(shí)現(xiàn)多個(gè)接口,并且需要實(shí)現(xiàn)所有的抽象方法。
- 區(qū)別:抽象類(lèi)可以包含靜態(tài)屬性和靜態(tài)方法或者普通方法,但是接口只能包含常量和抽象方法
抽象類(lèi)不能使private,但是接口只能是public的
子類(lèi)只能繼承一個(gè)抽象類(lèi),子類(lèi)可以實(shí)現(xiàn)多個(gè)接口 - 適用場(chǎng)景:接口相比抽象類(lèi)更加抽象,抽象類(lèi)是對(duì)事物的抽象,即對(duì)類(lèi)的抽象,而接口是對(duì)行為的抽象。抽象類(lèi)是對(duì)整個(gè)類(lèi)整體包含屬性,行為,但是接口只是對(duì)類(lèi)局部行為進(jìn)行抽象。比如鳥(niǎo)和飛機(jī)都可以飛,可以將鳥(niǎo)和飛機(jī)都設(shè)計(jì)成抽象類(lèi),將飛這個(gè)行為定義成接口,鳥(niǎo)和飛機(jī)都實(shí)現(xiàn)這個(gè)接口,都具有飛的行為了。更多類(lèi)型的鳥(niǎo)可以繼承鳥(niǎo)父類(lèi),更多種類(lèi)的飛機(jī)則可以進(jìn)行繼承飛機(jī)抽象類(lèi),所以這就是抽象類(lèi)和接口的區(qū)別。
簡(jiǎn)述java異常機(jī)制
- Java異常機(jī)制是一種識(shí)別和響應(yīng)錯(cuò)誤的機(jī)制,提高了程序的健壯性。Throwable是Error和Exception的父類(lèi),定義了一些捕獲和打印異常的方法。Java異常分為運(yùn)行時(shí)異常,都繼承于RunTimeException,編輯器不會(huì)檢查這類(lèi)異常,只有在運(yùn)行時(shí)才會(huì)捕獲或者拋出,比如除數(shù)為0引起的運(yùn)行時(shí)異常;還有一類(lèi)是檢查型異常,編輯器會(huì)檢查這類(lèi)異常是否拋出,或者是否被try catch 塊捕獲
簡(jiǎn)述java類(lèi)的初始化順序:
- 普通類(lèi): 靜態(tài)變量->靜態(tài)代碼塊->普通屬性->普通代碼塊->構(gòu)造函數(shù)
- 繼承了父類(lèi)的子類(lèi):父類(lèi)的靜態(tài)變量->父類(lèi)的靜態(tài)代碼塊->子類(lèi)的靜態(tài)變量->子類(lèi)的靜態(tài)代碼塊->父類(lèi)的普通變量->父類(lèi)的普通代碼塊->
父類(lèi)的構(gòu)造函數(shù)->子類(lèi)的普通變量->子類(lèi)的普通代碼塊->子類(lèi)的構(gòu)造函數(shù)
簡(jiǎn)述Java內(nèi)存區(qū)域
- Java內(nèi)存區(qū)域指的就是JVM的內(nèi)存區(qū)域,從劃分區(qū)域來(lái)講可以分為程序計(jì)數(shù)器,Java棧,堆,本地方法棧,方法區(qū);
- 程序計(jì)數(shù)器:線程私有區(qū)域,用來(lái)記錄每個(gè)線程指令執(zhí)行的地址,在JVM中,多線程的執(zhí)行是線程間輪流獲得CPU的執(zhí)行時(shí)間的,因此在某個(gè)時(shí)刻只有一條線程指令是被CPU內(nèi)核執(zhí)行,多線程間的切換需要記錄每個(gè)線程的執(zhí)行位置,因此每個(gè)線程都有自己獨(dú)立的程序計(jì)數(shù)器,并且不會(huì)互相干擾,因此程序計(jì)數(shù)器是每個(gè)線程私有區(qū)域。
- JAVA棧:線程私有區(qū)域,Java棧中存放的是棧幀,每個(gè)棧幀又包括局部變量表,操作數(shù)棧,指向當(dāng)前方法所屬類(lèi)的運(yùn)行時(shí)常量池的引用,方法返回地址等信息。當(dāng)執(zhí)行一個(gè)方法時(shí),該方法的棧幀入賬,當(dāng)方法執(zhí)行完畢后,該方法的棧幀出棧。
- 局部變量表:用來(lái)存儲(chǔ)方法的局部變量,如果是基本的數(shù)據(jù)類(lèi)型,存儲(chǔ)的則是局部變量的直接量,如果是引用類(lèi)型的變量,則存儲(chǔ)指向?qū)ο蟮囊?,局部變量的大小在編譯期就可以知道了,所以運(yùn)行期間局部變量表的大小不變。
- 操作數(shù)棧: 用來(lái)處理程序的計(jì)算過(guò)程
- 指向運(yùn)行時(shí)常量池的引用: 執(zhí)行運(yùn)行時(shí)所屬類(lèi)的運(yùn)行時(shí)常量池
- 方法返回地址:方法執(zhí)行完后需要返回到調(diào)用他的位置,因此需要存儲(chǔ)這個(gè)地址
每個(gè)線程的執(zhí)行方法是不同的,所以JAVA棧也是每個(gè)線程私有的。
- 本地方法棧: 跟Java棧類(lèi)似,不過(guò)本地方法棧存儲(chǔ)的是需要執(zhí)行的本地方法棧幀,本地方法是由其它語(yǔ)言編寫(xiě)的
- Java堆:線程共享區(qū)域,Java堆存儲(chǔ)的是數(shù)組和對(duì)象本身,JVM中只有一個(gè)Java堆,也是jvm垃圾回收的主要區(qū)域,如果堆內(nèi)存不夠來(lái)分配內(nèi)存實(shí)例則會(huì)出現(xiàn)內(nèi)存溢出
- 方法區(qū):現(xiàn)場(chǎng)共享區(qū)域,存儲(chǔ)著每個(gè)類(lèi)的基本信息包括,靜態(tài)變量常量,方法以及編譯期編譯后的代碼。方法區(qū)中有個(gè)重要的部分是運(yùn)行時(shí)常量池,運(yùn)行時(shí)常量池用來(lái)存儲(chǔ)編譯期生成的常量,當(dāng)然也可以動(dòng)態(tài)創(chuàng)建運(yùn)行時(shí)常量池空間,比如String,intern。
簡(jiǎn)述Java內(nèi)存模型
Java內(nèi)存模型是一組程序線程訪問(wèn)共享變量的規(guī)則。Java內(nèi)存模型中將線程私有數(shù)據(jù)的存儲(chǔ)區(qū)域定義為工作內(nèi)存,將線程間共享的變量數(shù)據(jù)定義為主內(nèi)存。
- 工作內(nèi)存為每個(gè)線程私有的內(nèi)存區(qū)域,存儲(chǔ)著線程的指令執(zhí)行位置,執(zhí)行方法的相關(guān)信息,每個(gè)線程不能訪問(wèn)其它線程工作內(nèi)存的數(shù)據(jù),因此工作內(nèi)存中的本地變量操作是線程安全的。
- 主內(nèi)存存儲(chǔ)著實(shí)例對(duì)象和其它的類(lèi)的基本信息,是多個(gè)線程間共有的,如果某個(gè)線程訪問(wèn)或者操作主內(nèi)存的同一個(gè)變量,先要從主內(nèi)存中刷新變量到線程的工作內(nèi)存中,計(jì)算完后將變量從工作內(nèi)存中刷新到主內(nèi)存中,當(dāng)多個(gè)線程訪問(wèn)或者操作的時(shí)候,則會(huì)出現(xiàn)變量不安全。
為了解決多線程間的執(zhí)行問(wèn)題,Java從原子性,一致性和可見(jiàn)性提供了解決方案。