java基礎(chǔ)小記

編譯機(jī)制
  編譯主要是把 .Java文件轉(zhuǎn)換為 .class 文件。其中轉(zhuǎn)換后的 .class 文件就包含了元數(shù)據(jù),方法信息等一些信息。比如說元數(shù)據(jù)就包含了 Java 文件中聲明的常量,也就是我們所說的常量池。

泛型實(shí)現(xiàn)原理
  Java泛型實(shí)現(xiàn)原理:類型擦除
  Java的泛型是偽泛型。在編譯期間,所有的泛型信息都會被擦除掉。正確理解泛型概念的首要前提是理解類型擦出(type erasure)。
  Java中的泛型基本上都是在編譯器這個層次來實(shí)現(xiàn)的?! ?br>   在生成的Java字節(jié)碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數(shù),會在編譯器在編譯的時候去掉。這個過程就稱為類型擦除。
  如在代碼中定義的List<object>和List<String>等類型,在編譯后都會變成List。JVM看到的只是List,而由泛型附加的類型信息對JVM來說是不可見的。Java編譯器會在編譯時盡可能的發(fā)現(xiàn)可能出錯的地方,但是仍然無法避免在運(yùn)行時刻出現(xiàn)類型轉(zhuǎn)換異常的情況。

編譯時期和運(yùn)行時期類型檢查
  Java中的許多對象(一般都是具有父子類關(guān)系的父類對象)在運(yùn)行時都會出現(xiàn)兩種類型:編譯時類型和運(yùn)行時類型,例如:Person person = new Student();這行代碼將會生成一個person變量,該變量的編譯時類型是Person,運(yùn)行時類型是Student。
  Java的引用變量有兩個類型,一個是編譯時類型,一個是運(yùn)行時類型,編譯時類型由聲明該變量時使用的類型決定,運(yùn)行時類型由實(shí)際賦給該變量的對象決定

多態(tài)實(shí)現(xiàn)原理
  基于繼承實(shí)現(xiàn)的多態(tài)可以總結(jié)如下:對于引用子類的父類類型,在處理該引用時,它適用于繼承該父類的所有子類,子類對象的不同,對方法的實(shí)現(xiàn)也就不同,執(zhí)行相同動作產(chǎn)生的行為也就不同。
  繼承是通過重寫父類的同一方法的幾個不同子類來體現(xiàn)的,那么就可以是通過實(shí)現(xiàn)接口并覆蓋接口中同一方法的幾不同的類體現(xiàn)的。
  在接口的多態(tài)中,指向接口的引用必須是指定這實(shí)現(xiàn)了該接口的一個類的實(shí)例程序,在運(yùn)行時,根據(jù)對象引用的實(shí)際類型來執(zhí)行對應(yīng)的方法。
  當(dāng)超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調(diào)用誰的成員方法,但是這個被調(diào)用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法,但是它仍然要根據(jù)繼承鏈中方法調(diào)用的優(yōu)先級來確認(rèn)方法,該優(yōu)先級為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

A繼承B,加載順序

  1. 要加載類A,則先加載執(zhí)行其父類B(Object)的靜態(tài)變量以及靜態(tài)語句塊(執(zhí)行先后順序按排列的先后順序)。
  2. 然后再加載執(zhí)行類A的靜態(tài)變量以及靜態(tài)語句塊。(并且1、2步驟只會執(zhí)行1次)
  3. 若需實(shí)例化類A,則先調(diào)用其父類B的構(gòu)造函數(shù),并且在調(diào)用其父類B的構(gòu)造函數(shù)前,依次先調(diào)用父類B中的非靜態(tài)變量及非靜態(tài)語句塊.最后再調(diào)用父類B中的構(gòu)造函數(shù)初始化。
  4. 然后再依次調(diào)用類A中的非靜態(tài)變量及非靜態(tài)語句塊.最后調(diào)用A中的構(gòu)造函數(shù)初始化。( 并且3、4步驟可以重復(fù)執(zhí)行)
  5. 而對于靜態(tài)方法和非靜態(tài)方法都是被動調(diào)用,即系統(tǒng)不會自動調(diào)用執(zhí)行,所以用戶沒有調(diào)用時都不執(zhí)行,主要區(qū)別在于靜態(tài)方法可以直接用類名直接調(diào)用(實(shí)例化對象也可以),而非靜態(tài)方法只能先實(shí)例化對象后才能調(diào)用。

serizeble有什么用
  序列化就是把一個對象保存到一個文件或數(shù)據(jù)庫字段中去,反序列化就是在適當(dāng)?shù)臅r候把這個文件再轉(zhuǎn)化成原來的對象使用。我想最主要的作用有:

  1. 在進(jìn)程下次啟動時讀取上次保存的對象的信息
  2. 在不同的AppDomain或進(jìn)程之間傳遞數(shù)據(jù)
  3. 在分布式應(yīng)用系統(tǒng)中傳遞數(shù)據(jù)

序列化

  1. 當(dāng)一個父類實(shí)現(xiàn)序列化,子類自動實(shí)現(xiàn)序列化,不需要顯式實(shí)現(xiàn)Serializable接口;
  2. 當(dāng)一個對象的實(shí)例變量引用其他對象,序列化該對象時也把引用對象進(jìn)行序列化;
  3. static,transient后的變量不能被序列化;

抽象類和接口區(qū)別:

  1. 接口是抽象類的變體,接口中所有的方法都是抽象的。而抽象類是聲明方法的存在而不去實(shí)現(xiàn)它的類。
  2. 接口可以多繼承,抽象類不行
  3. 接口定義方法,不能實(shí)現(xiàn),而抽象類可以實(shí)現(xiàn)部分方法。
  4. 接口中基本數(shù)據(jù)類型為static 而抽類象不是的。

JVM虛擬機(jī)結(jié)構(gòu)
JVM主要包括四個部分:

  1. 類加載器(ClassLoader):在JVM啟動時或者在類運(yùn)行時將需要的class加載到JVM中。
  2. 執(zhí)行引擎:負(fù)責(zé)執(zhí)行class文件中包含的字節(jié)碼指令(執(zhí)行引擎的工作機(jī)制,這里也不細(xì)說了,這里主要介紹JVM結(jié)構(gòu));
  3. 內(nèi)存區(qū)(也叫運(yùn)行時數(shù)據(jù)區(qū)):是在JVM運(yùn)行的時候操作所分配的內(nèi)存區(qū)。運(yùn)行時內(nèi)存區(qū)主要可以劃分為5個區(qū)域
      方法區(qū)(Method Area):用于存儲類結(jié)構(gòu)信息的地方,包括常量池、靜態(tài)變量、構(gòu)造函數(shù)等(JDK7 永久代,JDK metaspace)。雖然JVM規(guī)范把方法區(qū)描述為堆的一個邏輯部分,但它卻有個別名non-heap(非堆),所以大家不要搞混淆了。方法區(qū)還包含一個運(yùn)行時常量池。這部分區(qū)域不是線程所私有,而是各個線程所共享的。
      java堆(Heap):存儲java實(shí)例或者對象(對象和數(shù)組等實(shí)例)的地方。這塊是GC的主要區(qū)域(后面解釋)。從存儲的內(nèi)容我們可以很容易知道,方法區(qū)和堆是被所有java線程共享的。
      java棧(Stack):java??偸呛途€程關(guān)聯(lián)在一起,每當(dāng)創(chuàng)建一個線程時,JVM就會為這個線程創(chuàng)建一個對應(yīng)的java棧。在這個java棧中又會包含多個棧幀,每運(yùn)行一個方法就創(chuàng)建一個棧幀,用于存儲局部變量表、操作棧、方法返回值等。每一個方法從調(diào)用直至執(zhí)行完成的過程,就對應(yīng)一個棧幀在java棧中入棧到出棧的過程。所以java棧是線程私有的。
      程序計數(shù)器(PC Register):用于保存當(dāng)前線程執(zhí)行的內(nèi)存地址。由于JVM程序是多線程執(zhí)行的(線程輪流切換),所以為了保證線程切換回來后,還能恢復(fù)到原先狀態(tài),就需要一個獨(dú)立的計數(shù)器,記錄之前中斷的地方,可見程序計數(shù)器也是線程私有的。
      本地方法棧(Native Method Stack):和java棧的作用差不多,只不過是為JVM使用到的native方法服務(wù)的。
  4. 本地方法接口:主要是調(diào)用C或C++實(shí)現(xiàn)的本地方法及返回結(jié)果。

雙親委派模型
  工作過程是:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成, 每一個層次的類加載都是如此 ,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中,只有當(dāng)父加載器反饋?zhàn)约簾o法加載這個加載請求的時候,子加載器才會嘗試自己去加載。
  使用這種機(jī)制,可以避免重復(fù)加載,當(dāng)父親已經(jīng)加載了該類的時候,就沒有必要子ClassLoader再加載一次(試想如果有人編寫了一個惡意的基礎(chǔ)類,比如String類,并裝載到JVM中將會引起多么可怕的后果呢。但是,由于有了全盤負(fù)責(zé)委托機(jī)制,String類 永遠(yuǎn)是有根裝載器裝載,這樣就避免了事件的發(fā)生)。
  ClassLoader主要對類的請求提供服務(wù),當(dāng)JVM需要某類時,它根據(jù)名稱向ClassLoader要求這個類,然后由ClassLoader返回這個類的class對象。
  每當(dāng) JVM 啟動的時候,就會產(chǎn)生 三個 ClassLoader,它們分別是Bootstrap Loader, ExtClassLoader 和 AppClassLoader,ClassLoader就是用來動態(tài)加載class文件到內(nèi)存當(dāng)中用的。
  Bootstrap Classloader啟動類加載器,主要負(fù)責(zé)java_home/lib下的核心api或者-Xbootstrap選項(xiàng)指定的jar包裝入工作。
  Extension ClassLoader擴(kuò)展類加載器,主要負(fù)責(zé)java_home/lib/ext下jar包。
  App CLassLoader 系統(tǒng)類加載器,主要負(fù)責(zé)Java -classpath/所指的目錄下的類與jar包的裝入工作。
  UserCustom ClassLoader用戶自定義類加載器,在程序運(yùn)行期間,通過Java.lang.Classloader的子類動態(tài)加載class。
  ExtClassLoader的父類加載器是null,只不過在默認(rèn)的ClassLoader 的 loadClass 方法中,當(dāng)parent為null時,是交給BootStrapClassLoader來處理的,而且ExtClassLoader 沒有重寫默認(rèn)的loadClass方法,所以,ExtClassLoader也會調(diào)用BootStrapLoader類加載器來加載,這就導(dǎo)致“BootStrapClassLoader具備了ExtClassLoader父類加載器的功能”。
查看classloader的源碼可以發(fā)現(xiàn)三個重要的方法:
  loadClass。classloader加載類的入口,此方法負(fù)責(zé)加載指定名字的類,ClassLoader的實(shí)現(xiàn)方法為先從已經(jīng)加載的類中尋找,如沒有則繼續(xù)從父ClassLoader中尋找,如仍然沒找到,則從BootstrapClassLoader中尋找,最后再調(diào)用findClass方法來尋找,如要改變類的加載順序,則可覆蓋此方法,如加載順序相同,則可通過覆蓋findClass來做特殊的處理,例如解密、固定路徑尋找等,當(dāng)通過整個尋找類的過程仍然未獲取到Class對象時,則拋出ClassNotFoundException。如類需要resolve,則調(diào)用resolveClass進(jìn)行鏈接。
  findClass。它接受要加載的類作為它的參數(shù),在該方法中會找到class文件并且讀取文件中的內(nèi)容到一個 byte 數(shù)組。此方法直接拋出ClassNotFoundException,因此需要通過覆蓋loadClass或此方法來以自定義的方式加載相應(yīng)的類。
  defineClass。此方法負(fù)責(zé)將二進(jìn)制的字節(jié)碼轉(zhuǎn)換為Class對象,這個方法對于自定義加載類而言非常重要,如二進(jìn)制的字節(jié)碼的格式不符合JVM Class文件的格式,拋出ClassFormatError;如需要生成的類名和二進(jìn)制字節(jié)碼中的不同,則拋出NoClassDefFoundError;如需要加載的class是受保護(hù)的、采用不同簽名的或類名是以java.開頭的,則拋出SecurityException;如需加載的class在此ClassLoader中已加載,則拋出LinkageError。

導(dǎo)致Gc的情況:

  1. tenured被寫滿
  2. perm被寫滿
  3. System.gc()的顯式調(diào)用。
  4. 上一次GC之后heap的各域分配策略動態(tài)變化。

JVM分別對新生代和舊生代采用不同的垃圾回收機(jī)制
  將對象按其生命周期的不同劃分成:年輕代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)
  常見檢測出垃圾算法:
    引用計數(shù)法
    可達(dá)性分析算法
  新生代的GC(Minor GC): 指發(fā)生在新生代的垃圾收集動作,因?yàn)?Java 對象大多都具備朝生夕滅的特性,所以 Minor GC 非常頻繁,一般回收速度也比較快。新生代通常存活時間較短,因此基于Copying算法來進(jìn)行回收,所謂Copying算法就是掃描出存活的對象,并復(fù)制到一塊新的完全未使用的空間中,對應(yīng)于新生代,就是在Eden和FromSpace或ToSpace之間copy。
  新生代采用空閑指針的方式來控制GC觸發(fā),指針保持最后一個分配的對象在新生代區(qū)間的位置,當(dāng)有新的對象要分配內(nèi)存時,用于檢查空間是否足夠,不夠就觸發(fā)GC。當(dāng)連續(xù)分配對象時,對象會逐漸從eden到survivor,最后到舊生代。
  舊生代的GC(Major GC / Full GC):指發(fā)生在老年代的 GC。舊生代與新生代不同,對象存活的時間比較長,比較穩(wěn)定,因此采用標(biāo)記(Mark)算法來進(jìn)行回收,所謂標(biāo)記就是掃描出存活的對象,然后再進(jìn)行回收未被標(biāo)記的對象,回收后對用空出的空間要么進(jìn)行合并,要么標(biāo)記出來便于下次進(jìn)行分配,總之就是要減少內(nèi)存碎片帶來的效率損耗。 MajorGC 的速度一般會比 Minor GC 慢 10倍以上。Thinking in java給Java gc取了一個羅嗦的稱呼:“自適應(yīng)、分代的、停止-復(fù)制、標(biāo)記-掃描”式的垃圾回收器。

JVM調(diào)優(yōu)
從以下幾個方面進(jìn)行:
  線程池:解決用戶響應(yīng)時間長的問題
  連接池
  JVM啟動參數(shù):調(diào)整各代的內(nèi)存比例和垃圾回收算法,提高吞吐量
  程序算法:改進(jìn)程序邏輯算法提高性能

內(nèi)存泄露:
  概括地說,這就是內(nèi)存托管語言中的內(nèi)存泄漏產(chǎn)生的主要原因:保留下來卻永遠(yuǎn)不再使用的對象引用。

  1. 全局集合
  2. 緩存
      典型的算法是:
      檢查結(jié)果是否在緩存中,如果在,就返回結(jié)果。
      如果結(jié)果不在緩存中,就進(jìn)行計算。
      將計算出來的結(jié)果添加到緩存中,以便以后對該操作的調(diào)用可以使用。
      該算法的問題(或者說是潛在的內(nèi)存泄漏)出在最后一步。如果調(diào)用該操作時有相當(dāng)多的不同輸入,就將有相當(dāng)多的結(jié)果存儲在緩存中。很明顯這不是正確的方法。
      為了預(yù)防這種具有潛在破壞性的設(shè)計,程序必須確保對于緩存所使用的內(nèi)存容量有一個上限。因此,更好的算法是:
      檢查結(jié)果是否在緩存中,如果在,就返回結(jié)果。
      如果結(jié)果不在緩存中,就進(jìn)行計算。
      如果緩存所占的空間過大,就移除緩存最久的結(jié)果。
      將計算出來的結(jié)果添加到緩存中,以便以后對該操作的調(diào)用可以使用
  3. ClassLoader
      ClassLoader的特別之處在于它不僅涉及“常規(guī)”的對象引用,還涉及元對象引用,比如:字段、方法和類。這意味著只要有對字段、方法、類或ClassLoader的對象的引用,ClassLoader就會駐留在JVM中。因?yàn)镃lassLoader本身可以關(guān)聯(lián)許多類及其靜態(tài)字段,所以就有許多內(nèi)存被泄漏了。

volatile關(guān)鍵字怎么實(shí)現(xiàn)
  可見性的意思是當(dāng)一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。
  如果大家有興趣查看代碼JIT生成后的匯編指令,會發(fā)現(xiàn)針對volatile的變量的寫操作,會有一個Lock指令,這是用來實(shí)現(xiàn)內(nèi)存屏障的,保證如果一個處理器修改了變量值,會直接將值寫回到內(nèi)存,其他的處理器對應(yīng)的緩存也會失效,需要重新從內(nèi)存中讀取,這樣就保證所有的處理器讀到的值,都是最近的變量值。將當(dāng)前處理器緩存行的數(shù)據(jù)會寫回到系統(tǒng)內(nèi)存。這個寫回內(nèi)存的操作會引起在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無效。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,687評論 18 399
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,797評論 11 349
  • 一 、java虛擬機(jī)底層結(jié)構(gòu)詳解 我們知道,一個JVM實(shí)例的行為不光是它自己的事,還涉及到它的子系統(tǒng)、存儲區(qū)域、...
    葡萄喃喃囈語閱讀 1,582評論 0 4
  • 《深入理解Java虛擬機(jī)》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,472評論 1 34
  • 莫聽穿林打葉聲,何妨吟嘯且徐行。竹杖芒鞋輕勝馬,誰怕!一蓑煙雨任平生。料峭春風(fēng)吹酒醒,微冷,山頭斜照卻相迎。回首向...
    picspin閱讀 539評論 0 2

友情鏈接更多精彩內(nèi)容