備戰金三銀四!一線互聯網公司java崗面試題整理:Java基礎+多線程+集合+JVM合集!

前言

回首來看2020年,真的是印象中過的最快的一年了,真的是時間過的飛快,還沒反應過來年就誇完了,相信你們也已經開始上班了!俗話說新年新氣象,立刻就要到了一年之中最重要的金三銀四,以前一直有粉絲要求我整理一些java崗的面試題,年前一直沒時間,此次趁着元旦節給你們整理了一些一線互聯網公司java崗面試題主要是Java基礎+多線程+集合+JVM,滿滿的乾貨放在下面了!內容有點多,你們能夠挑選本身須要的部分看!java

Java 語⾔有哪些特色?

  • 簡單易學;
  • ⾯向對象(封裝,繼承,多態);
  • 平臺⽆關性( Java 虛擬機實現平臺⽆關性);
  • 可靠性;
  • 安全性;
  • ⽀持多線程( C++ 語⾔沒有內置的多線程機制,所以必須調⽤操做系統的多線程功能來進⾏多線程程序設計,⽽ Java 語⾔卻提供了多線程⽀持);

⾯向對象和⾯向過程的區別

  • ⾯向過程 :⾯向過程性能⽐⾯向對象⾼。 由於類調⽤時須要實例化,開銷⽐᫾⼤,⽐᫾消耗資源,因此當性能是最重要的考量因素的時候,⽐如單⽚機、嵌⼊式開發、Linux/Unix 等⼀般採⽤⾯向過程開發。可是,⾯向過程沒有⾯向對象易維護、易復⽤、易擴展。
  • ⾯向對象 :⾯向對象易維護、易復⽤、易擴展。 由於⾯向對象有封裝、繼承、多態性的特性,因此能夠設計出低耦合的系統,使系統更加靈活、更加易於維護。可是,⾯向對象性能⽐⾯向過程低。

什麼是java虛擬機

  • Java 虛擬機(JVM)是運⾏ Java 字節碼的虛擬機。JVM 有針對不一樣系統的特定實現(Windows,Linux,macOS),⽬的是使⽤相同的字節碼,它們都會給出相同的結果。

什麼是字節碼?採⽤字節碼的好處是什麼?

  • 在 Java 中,JVM 能夠理解的代碼就叫作 字節碼 (即擴展名爲 .class 的⽂件),它不⾯向任何特定的處理器,只⾯向虛擬機。Java 語⾔經過字節碼的⽅式,在⼀定程度上解決了傳統解釋型語⾔執⾏效率低的問題,同時⼜保留了解釋型語⾔可移植的特色。因此 Java 程序運⾏時⾼效,⽽且,因爲字節碼並不針對⼀種特定的機器,所以,Java 程序⽆須從新編譯即可在多種不一樣操做系統的計算機上運⾏。

關於JVM和字節碼

  • Java 虛擬機(JVM)是運⾏ Java 字節碼的虛擬機。JVM 有針對不一樣系統的特定實現(Windows,Linux,macOS),⽬的是使⽤相同的字節碼,它們都會給出相同的結果。字節碼和不一樣系統的 JVM 實現是 Java 語⾔「⼀次編譯,隨處能夠運⾏」的關鍵所在。

JDK 和 JRE

  • JDK 是 Java Development Kit,它是功能⻬全的 Java SDK。它擁有 JRE 所擁有的⼀切,還有編譯器(javac)和⼯具(如 javadoc 和 jdb)。它可以建立和編譯程序。
  • JRE 是 Java 運⾏時環境。它是運⾏已編譯 Java 程序所需的全部內容的集合,包括 Java 虛擬機(JVM),Java 類庫,java 命令和其餘的⼀些基礎構件。可是,它不能⽤於建立新程序。

Oracle JDK 和 OpenJDK 的對⽐

  • Oracle JDK ⼤概每 6 個⽉發⼀次主要版本,⽽ OpenJDK 版本⼤概每三個⽉發佈⼀次。但這不是固定的,我以爲了解這個沒啥⽤處。
  • OpenJDK 是⼀個參考模型而且是徹底開源的,⽽ Oracle JDK 是 OpenJDK 的⼀個實現,並非徹底開源的;
  • Oracle JDK ⽐ OpenJDK 更穩定。OpenJDK 和 Oracle JDK 的代碼⼏乎相同,但 Oracle JDK 有更多的類和⼀些錯誤修復。所以,若是您想開發企業/商業軟件,我建議您選擇 Oracle JDK,由於它通過了完全的測試和穩定。某些狀況下,有些⼈提到在使⽤ OpenJDK 可能會遇到了許多應⽤程序崩潰的問題,可是,只需切換到 Oracle JDK 就能夠解決問題;
  • 在響應性和 JVM 性能⽅⾯,Oracle JDK 與 OpenJDK 相⽐提供了更好的性能;
  • Oracle JDK 不會爲即將發佈的版本提供⻓期⽀持,⽤戶每次都必須經過更新到最新版本得到⽀持來獲取最新版本;
  • Oracle JDK 根據⼆進制代碼許可協議得到許可,⽽ OpenJDK 根據 GPL v2 許可得到許可。

什麼是 Java 程序的主類 應⽤程序和⼩程序的主類有何不一樣?

  • ⼀個程序中能夠有多個類,但只能有⼀個類是主類。在 Java 應⽤程序中,這個主類是指包含main()⽅法的類。⽽在 Java ⼩程序中,這個主類是⼀個繼承⾃系統類 JApplet 或 Applet 的⼦類。應⽤程序的主類不⼀定要求是 public 類,但⼩程序的主類要求必須是 public 類。主類是 Java程序執⾏的⼊⼝點。

Java 應⽤程序與⼩程序之間有哪些差異?

  • 簡單說應⽤程序是從主線程啓動(也就是 main() ⽅法)。applet ⼩程序沒有 main() ⽅法,主要是嵌在瀏覽器⻚⾯上運⾏(調⽤ init() 或者 run() 來啓動),嵌⼊瀏覽器這點跟 flash 的⼩遊戲相似。

字符型常量和字符串常量的區別?

  • 形式上: 字符常量是單引號引發的⼀個字符; 字符串常量是雙引號引發的若⼲個字符
  • 含義上: 字符常量至關於⼀個整型值( ASCII 值),能夠參加表達式運算; 字符串常量表明⼀個地址值(該字符串在內存中存放位置)
  • 佔內存⼤⼩ 字符常量只佔 2 個字節; 字符串常量佔若⼲個字節 (注意: char 在 Java 中佔兩個字節)

構造器 Constructor 是否可被 override?

  • Constructor 不能被 override(重寫),可是能夠 overload(重載),因此你能夠看到⼀個類中有多個構造函數的狀況。

重載和重寫的區別

  • 重載就是一樣的⼀個⽅法可以根據輸⼊數據的不一樣,作出不一樣的處理
  • 重寫就是當⼦類繼承⾃⽗類的相同⽅法,輸⼊數據⼀樣,但要作出有別於⽗類的響應時,你就要覆蓋⽗類⽅法

說一下Java ⾯向對象編程三⼤特性: 封裝 繼承 多態

封裝

  • 封裝把⼀個對象的屬性私有化,同時提供⼀些能夠被外界訪問的屬性的⽅法,若是屬性不想被外界訪問,咱們⼤可沒必要提供⽅法給外界訪問。可是若是⼀個類沒有提供給外界訪問的⽅法,那麼這個類也沒有什麼意義了。

繼承

  • 繼承是使⽤已存在的類的定義做爲基礎建⽴新類的技術,新類的定義能夠增長新的數據或新的功能,也
    能夠⽤⽗類的功能,但不能選擇性地繼承⽗類。經過使⽤繼承咱們可以⾮常⽅便地復⽤之前的代碼。

關於繼承以下 3 點請記住:

  • ⼦類擁有⽗類對象全部的屬性和⽅法(包括私有屬性和私有⽅法),可是⽗類中的私有屬性和⽅
    法⼦類是⽆法訪問,只是擁有。
  • ⼦類能夠擁有⾃⼰屬性和⽅法,即⼦類能夠對⽗類進⾏擴展。
  • ⼦類能夠⽤⾃⼰的⽅式實現⽗類的⽅法。(之後介紹)。

多態

  • 所謂多態就是指程序中定義的引⽤變量所指向的具體類型和經過該引⽤變量發出的⽅法調⽤在編程時並不肯定,⽽是在程序運⾏期間才肯定,即⼀個引⽤變量到底會指向哪一個類的實例對象,該引⽤變量發出的⽅法調⽤究竟是哪一個類中實現的⽅法,必須在由程序運⾏期間才能決定。在 Java 中有兩種形式能夠實現多態:繼承(多個⼦類對同⼀⽅法的重寫)和接⼝(實現接⼝並覆蓋接⼝中同⼀⽅法)。

說一下⾃動裝箱與拆箱

  • 裝箱:將基本類型⽤它們對應的引⽤類型包裝起來;
  • 拆箱:將包裝類型轉換爲基本數據類型;

在⼀個靜態⽅法內調⽤⼀個⾮靜態成員爲何是⾮法的?

因爲靜態⽅法能夠不經過對象進⾏調⽤,所以在靜態⽅法⾥,不能調⽤其餘⾮靜態變量,也不能夠訪問⾮靜態變量成員。面試

在 Java 中定義⼀個不作事且沒有參數的構造⽅法的做⽤

  • Java 程序在執⾏⼦類的構造⽅法以前,若是沒有⽤ super() 來調⽤⽗類特定的構造⽅法,則會調⽤⽗類中「沒有參數的構造⽅法」。所以,若是⽗類中只定義了有參數的構造⽅法,⽽在⼦類的構造⽅法中⼜沒有⽤ super() 來調⽤⽗類中特定的構造⽅法,則編譯時將發⽣錯誤,由於 Java 程序在⽗類中找不到沒有參數的構造⽅法可供執⾏。解決辦法是在⽗類⾥加上⼀個不作事且沒有參數的構造⽅法。

import java 和 javax 有什麼區別?

  • 剛開始的時候 JavaAPI 所必需的包是 java 開頭的包,javax 當時只是擴展 API 包來使⽤。然⽽隨着時間的推移,javax 逐漸地擴展成爲 Java API 的組成部分。可是,將擴展從 javax 包移動到 java包確實太麻煩了,最終會破壞⼀堆現有的代碼。所以,最終決定 javax 包將成爲標準 API 的⼀部分。因此,實際上 java 和 javax 沒有區別。這都是⼀個名字。

接⼝和抽象類的區別是什麼?

  • 接⼝的⽅法默認是 public,全部⽅法在接⼝中不能有實現(Java 8 開始接⼝⽅法能夠有默認實現),⽽抽象類能夠有⾮抽象的⽅法。
  • 接⼝中除了 static、final 變量,不能有其餘變量,⽽抽象類中則不⼀定。
  • ⼀個類能夠實現多個接⼝,但只能實現⼀個抽象類。接⼝⾃⼰自己能夠經過 extends 關鍵字擴
    展多個接⼝。
  • 接⼝⽅法默認修飾符是 public,抽象⽅法能夠有 public、protected 和 default 這些修飾符(抽象⽅法就是爲了被重寫因此不能使⽤ private 關鍵字修飾!)。
  • 從設計層⾯來講,抽象是對類的抽象,是⼀種模板設計,⽽接⼝是對⾏爲的抽象,是⼀種⾏爲的規範。

成員變量與局部變量的區別有哪些?

  1. 從語法形式上看:成員變量是屬於類的,⽽局部變量是在⽅法中定義的變量或是⽅法的參數;成
    員變量能夠被 public,private,static 等修飾符所修飾,⽽局部變量不能被訪問控制修飾符及
    static 所修飾;可是,成員變量和局部變量都能被 final 所修飾。
  2. 從變量在內存中的存儲⽅式來看:若是成員變量是使⽤ static 修飾的,那麼這個成員變量是屬
    於類的,若是沒有使⽤ static 修飾,這個成員變量是屬於實例的。對象存於堆內存,若是局部
    變量類型爲基本數據類型,那麼存儲在棧內存,若是爲引⽤數據類型,那存放的是指向堆內存對
    象的引⽤或者是指向常量池中的地址。
  3. 從變量在內存中的⽣存時間上看:成員變量是對象的⼀部分,它隨着對象的建立⽽存在,⽽局部
    變量隨着⽅法的調⽤⽽⾃動消失。
  4. 成員變量若是沒有被賦初值:則會⾃動以類型的默認值⽽賦值(⼀種狀況例外:被 final 修飾的
    成員變量也必須顯式地賦值),⽽局部變量則不會⾃動賦值。

建立⼀個對象⽤什麼運算符?對象實體與對象引⽤有何不一樣?

  • new 運算符,new 建立對象實例(對象實例在堆內存中),對象引⽤指向對象實例(對象引⽤存放在棧內存中)。⼀個對象引⽤能夠指向 0 個或 1 個對象(⼀根繩⼦能夠不繫⽓球,也能夠系⼀個⽓球);⼀個對象能夠有 n 個引⽤指向它(能夠⽤ n 條繩⼦繫住⼀個⽓球)。

什麼是⽅法的返回值?返回值在類的⽅法⾥的做⽤是什麼?

  • ⽅法的返回值是指咱們獲取到的某個⽅法體中的代碼執⾏後產⽣的結果!(前提是該⽅法可能產⽣結果)。返回值的做⽤:接收出結果,使得它能夠⽤於其餘的操做!

⼀個類的構造⽅法的做⽤是什麼? 若⼀個類沒有聲明構造⽅法,該程序能正確執⾏嗎? 爲何?

  • 主要做⽤是完成對類對象的初始化⼯做。能夠執⾏。由於⼀個類即便沒有聲明構造⽅法也會有默認的不
    帶參數的構造⽅法。

構造⽅法有哪些特性?

  • 名字與類名相同。
  • 沒有返回值,但不能⽤ void 聲明構造函數。
  • ⽣成類的對象時⾃動執⾏,⽆需調⽤。

靜態⽅法和實例⽅法有何不一樣

  • 在外部調⽤靜態⽅法時,可使⽤"類名.⽅法名"的⽅式,也可使⽤"對象名.⽅法名"的⽅式。
    ⽽實例⽅法只有後⾯這種⽅式。也就是說,調⽤靜態⽅法能夠⽆需建立對象。
  • 靜態⽅法在訪問本類的成員時,只容許訪問靜態成員(即靜態成員變量和靜態⽅法),⽽不容許
    訪問實例成員變量和實例⽅法;實例⽅法則⽆此限制。

對象的相等與指向他們的引⽤相等,二者有什麼不一樣?

  • 對象的相等,⽐的是內存中存放的內容是否相等。⽽引⽤相等,⽐᫾的是他們指向的內存地址是否相
    等。

在調⽤⼦類構造⽅法以前會先調⽤⽗類沒有參數的構造⽅法,其⽬的是?

  • 幫助⼦類作初始化⼯做。

簡述線程、程序、進程的基本概念。以及他們之間關係是什麼?

  • 線程與進程類似,但線程是⼀個⽐進程更⼩的執⾏單位。⼀個進程在其執⾏的過程當中能夠產⽣多個線程。與進程不一樣的是同類的多個線程共享同⼀塊內存空間和⼀組系統資源,因此係統在產⽣⼀個線程,或是在各個線程之間做切換⼯做時,負擔要⽐進程⼩得多,也正由於如此,線程也被稱爲輕量級進程。編程

  • 程序是含有指令和數據的⽂件,被存儲在磁盤或其餘的數據存儲設備中,也就是說程序是靜態的代碼。瀏覽器

  • 進程是程序的⼀次執⾏過程,是系統運⾏程序的基本單位,所以進程是動態的。系統運⾏⼀個程序便是⼀個進程從建立,運⾏到消亡的過程。簡單來講,⼀個進程就是⼀個執⾏中的程序,它在計算機中⼀個指令接着⼀個指令地執⾏着,同時,每一個進程還佔有某些系統資源如 CPU 時間,內存空間,⽂件,輸⼊輸出設備的使⽤權等等。換句話說,當程序在執⾏時,將會被操做系統載⼊內存中。 線程是進程劃分紅的更⼩的運⾏單位。線程和進程最⼤的不一樣在於基本上各進程是獨⽴的,⽽各線程則不⼀定,由於同⼀進程中的線程極有可能會相互影響。從另⼀⻆度來講,進程屬於操做系統的範疇,主要是同⼀段時間內,能夠同時執⾏⼀個以上的程序,⽽線程則是在同⼀程序內⼏乎同時執⾏⼀個以上的程序段。緩存

關於 final 關鍵字的⼀些總結

  • final 關鍵字主要⽤在三個地⽅:變量、⽅法、類。
  • 對於⼀個 final 變量,若是是基本數據類型的變量,則其數值⼀旦在初始化以後便不能更改;若是是引⽤類型的變量,則在對其初始化以後便不能再讓其指向另⼀個對象。
  • 當⽤ final 修飾⼀個類時,代表這個類不能被繼承。final 類中的全部成員⽅法都會被隱式地指定爲 final ⽅法。
  • 使⽤ final ⽅法的緣由有兩個。第⼀個緣由是把⽅法鎖定,以防任何繼承類修改它的含義;第⼆個緣由是效率。在早期的 Java 實現版本中,會將 final ⽅法轉爲內嵌調⽤。可是若是⽅法過於龐⼤,可能看不到內嵌調⽤帶來的任何性能提高(如今的 Java 版本已經不須要使⽤ final⽅法進⾏這些優化了)。類中全部的 private ⽅法都隱式地指定爲 final。

Java 中的異常處理

Java 異常類層次結構圖

  • 在 Java 中,全部的異常都有⼀個共同的祖先 java.lang 包中的 Throwable 類。Throwable: 有兩個重要的⼦類:Exception(異常) 和 Error(錯誤) ,⼆者都是 Java 異常處理的重要⼦類,各⾃都包含⼤量⼦類。
  • Error(錯誤):是程序⽆法處理的錯誤,表示運⾏應⽤程序中᫾嚴重問題。⼤多數錯誤與代碼編寫者執⾏的操做⽆關,⽽表示代碼運⾏時 JVM(Java 虛擬機)出現的問題。例如,Java 虛擬機運⾏錯誤(Virtual MachineError),當 JVM 再也不有繼續執⾏操做所需的內存資源時,將出現
  • OutOfMemoryError。這些異常發⽣時,Java 虛擬機(JVM)⼀般會選擇線程終⽌。這些錯誤表示故障發⽣於虛擬機⾃身、或者發⽣在虛擬機試圖執⾏應⽤時,如 Java 虛擬機運⾏錯誤(Virtual MachineError)、類定義錯誤(NoClassDefFoundError)等。這些錯誤是不可查的,由於它們在應⽤程序的控制和處理能⼒之 外,⽽且絕⼤多數是程序運⾏時不容許出現的情況。對於設計合理的應⽤程序來講,即便確實發⽣了錯誤,本質上也不該該試圖去處理它所引發的異常情況。在 Java中,錯誤經過 Error 的⼦類描述。
  • Exception(異常):是程序自己能夠處理的異常。Exception 類有⼀個重要的⼦類RuntimeExceptionRuntimeException 異常由 Java 虛擬機拋出。NullPointerException(要訪問的變量沒有引⽤任何對象時,拋出該異常)、ArithmeticException(算術運算異常,⼀個整數除以 0時,拋出該異常)和 ArrayIndexOutOfBoundsException (下標越界異常)。
  • 注意:異常和錯誤的區別:異常能被程序自己處理,錯誤是⽆法處理。

Throwable 類常⽤⽅法

  • public string getMessage():返回異常發⽣時的簡要描述
  • public string toString():返回異常發⽣時的詳細信息
  • public string getLocalizedMessage():返回異常對象的本地化信息。使⽤ Throwable 的⼦類覆蓋這個⽅法,能夠⽣成本地化信息。若是⼦類沒有覆蓋該⽅法,則該⽅法返回的信息與getMessage()返回的結果相同
  • public void printStackTrace():在控制檯上打印 Throwable 對象封裝的異常信息

異常處理總結

  • try 塊: ⽤於捕獲異常。其後可接零個或多個 catch 塊,若是沒有 catch 塊,則必須跟⼀個finally 塊。
  • catch 塊: ⽤於處理 try 捕獲到的異常。
  • finally 塊: ⽆論是否捕獲或處理異常,finally 塊⾥的語句都會被執⾏。當在 try 塊或catch 塊中遇到 return 語句時,finally 語句塊將在⽅法返回以前被執⾏。

在如下 4 種特殊狀況下,finally 塊不會被執⾏:

  • 在 finally 語句塊第⼀⾏發⽣了異常。 由於在其餘⾏,finally 塊仍是會獲得執⾏
  • 在前⾯的代碼中⽤了 System.exit(int)已退出程序。 exit 是帶參函數 ;若該語句在異常語句以後,finally 會執⾏
  • 程序所在的線程死亡。
  • 關閉 CPU。

Java 序列化中若是有些字段不想進⾏序列化,怎麼辦?

  • 對於不想進⾏序列化的變量,使⽤ transient 關鍵字修飾。transient 關鍵字的做⽤是:阻⽌實例中那些⽤此關鍵字修飾的的變量序列化;當對象被反序列化時,被 transient 修飾的變量值不會被持久化和恢復。transient 只能修飾變量,不能修飾類和⽅法。

獲取⽤鍵盤輸⼊常⽤的兩種⽅法

⽅法 1:經過 Scanner

⽅法 2:經過 BufferedReader

講一下Java 中 IO 流

Java 中 IO 流分爲⼏種?

  • 按照流的流向分,能夠分爲輸⼊流和輸出流;
  • 按照操做單元劃分,能夠劃分爲字節流和字符流;
  • 按照流的⻆⾊劃分爲節點流和處理流。
    Java Io 流共涉及 40 多個類,這些類看上去很雜亂,但實際上頗有規則,⽽且彼此之間存在⾮常緊密的聯繫, Java I0 流的 40 多個類都是從以下 4 個抽象類基類中派⽣出來的。
  • InputStream/Reader: 全部的輸⼊流的基類,前者是字節輸⼊流,後者是字符輸⼊流。
  • OutputStream/Writer: 全部輸出流的基類,前者是字節輸出流,後者是字符輸出流。

按操做⽅式分類結構圖:

按操做對象分類結構圖:

既然有了字節流,爲何還要有字符流?

  • 字符流是由 Java 虛擬機將字節轉換獲得的,問題就出在這個過程還算是⾮常耗時,而且,若是咱們不知道編碼類型就很容易出現亂碼問題。因此, I/O 流就⼲脆提供了⼀個直接操做字符的接⼝,⽅便咱們平時對字符進⾏流操做。若是⾳頻⽂件、圖⽚等媒體⽂件⽤字節流⽐᫾好,若是涉及到字符的話使⽤字符流⽐好。

講一下深拷⻉ vs 淺拷⻉

  • 淺拷⻉:對基本數據類型進⾏值傳遞,對引⽤數據類型進⾏引⽤傳遞般的拷⻉,此爲淺拷⻉。
  • 深拷⻉:對基本數據類型進⾏值傳遞,對引⽤數據類型,建立⼀個新的對象,並複製其內容,此
    爲深拷⻉。

說說List,Set,Map三者的區別?

  • List(對付順序的好幫⼿): List接⼝存儲⼀組不惟⼀(能夠有多個元素引⽤相同的對象),有序的對象
  • Set(注重獨⼀⽆⼆的性質): 不容許重複的集合。不會有多個元素引⽤相同的對象。
  • Map(⽤Key來搜索的專家): 使⽤鍵值對存儲。Map會維護與Key有關聯的值。兩個Key能夠引⽤相同的對象,但Key不能重複,典型的Key是String類型,但也能夠是任何對象。

HashMap 和 Hashtable 的區別

  • 線程是否安全: HashMap 是⾮線程安全的,HashTable 是線程安全的;HashTable 內部的⽅法基本都通過 synchronized 修飾。(若是你要保證線程安全的話就使⽤ ConcurrentHashMap吧!);
  • 效率: 由於線程安全的問題,HashMap 要⽐ HashTable 效率⾼⼀點。另外,HashTable 基本被淘汰,不要在代碼中使⽤它;
  • 對Null key 和Null value的⽀持: HashMap 中,null 能夠做爲鍵,這樣的鍵只有⼀個,能夠有⼀個或多個鍵所對應的值爲 null。。可是在 HashTable 中 put 進的鍵值只要有⼀個 null,直接拋出 NullPointerException。
  • 初始容量⼤⼩和每次擴充容量⼤⼩的不一樣 : ①建立時若是不指定容量初始值,Hashtable 默認的初始⼤⼩爲11,以後每次擴充,容量變爲原來的2n+1。HashMap 默認的初始化⼤⼩爲16。以後每次擴充,容量變爲原來的2倍。②建立時若是給定了容量初始值,那麼 Hashtable 會直接使⽤你給定的⼤⼩,⽽ HashMap 會將其擴充爲2的冪次⽅⼤⼩(HashMap 中的 tableSizeFor() ⽅法保證,下⾯給出了源代碼)。也就是說 HashMap 老是使⽤2的冪做爲哈希表的⼤⼩,後⾯會介紹到爲何是2的冪次⽅。
  • 底層數據結構: JDK1.8 之後的 HashMap 在解決哈希衝突時有了⼤的變化,當鏈表⻓度⼤於閾值(默認爲8)時,將鏈表轉化爲紅⿊樹,以減小搜索時間。Hashtable 沒有這樣的機制。

什麼是線程和進程?

何爲進程?

  • 進程是程序的⼀次執⾏過程,是系統運⾏程序的基本單位,所以進程是動態的。系統運⾏⼀個程序便是⼀個進程從建立,運⾏到消亡的過程。
  • 在 Java 中,當咱們啓動 main 函數時其實就是啓動了⼀個 JVM 的進程,⽽ main 函數所在的線程就是這個進程中的⼀個線程,也稱主線程。

何爲線程?

  • 線程與進程類似,但線程是⼀個⽐進程更⼩的執⾏單位。⼀個進程在其執⾏的過程當中能夠產⽣多個線程。與進程不一樣的是同類的多個線程共享進程的堆和⽅法區資源,但每一個線程有⾃⼰的程序計數器、虛擬機棧和本地⽅法棧,因此係統在產⽣⼀個線程,或是在各個線程之間做切換⼯做時,負擔要⽐進程⼩得多,也正由於如此,線程也被稱爲輕量級進程。

爲何要使⽤多線程呢?

  • 從計算機底層來講: 線程能夠⽐做是輕量級的進程,是程序執⾏的最⼩單位,線程間的切換和調度的成本遠遠⼩於進程。另外,多核 CPU 時代意味着多個線程能夠同時運⾏,這減小了線程上下⽂切換的開銷。
  • 從當代互聯⽹發展趨勢來講: 如今的系統動不動就要求百萬級甚⾄千萬級的併發量,⽽多線程併發編程正是開發⾼併發系統的基礎,利⽤好多線程機制能夠⼤⼤提⾼系統總體的併發能⼒以及性能

併發編程的三個重要特性

  • 原⼦性 : ⼀個的操做或者屢次操做,要麼全部的操做所有都獲得執⾏而且不會收到任何因素的⼲擾⽽中斷,要麼全部的操做都執⾏,要麼都不執⾏。 synchronized 能夠保證代碼⽚段的原⼦性。
  • 可⻅性 :當⼀個變量對共享變量進⾏了修改,那麼另外的線程都是⽴便可以看到修改後的最新值。 volatile 關鍵字能夠保證共享變量的可⻅性。
  • 有序性 :代碼在執⾏的過程當中的前後順序,Java 在編譯器以及運⾏期間的優化,代碼的執⾏順序未必就是編寫代碼時候的順序。 volatile 關鍵字能夠禁⽌指令進⾏重排序優化。

簡單的介紹⼀下強引⽤,軟引⽤,弱引⽤,虛引⽤

強引⽤(StrongReference)

  • 之前咱們使⽤的⼤部分引⽤實際上都是強引⽤,這是使⽤最廣泛的引⽤。若是⼀個對象具備強引⽤,那就相似於必不可少的⽣活⽤品,垃圾回收器毫不會回收它。當內存空 間不⾜,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終⽌,也不會靠隨意回收具備強引⽤的對象來解決內存不⾜問題。

軟引⽤(SoftReference)

  • 若是⼀個對象只具備軟引⽤,那就相似於可有可⽆的⽣活⽤品。若是內存空間⾜夠,垃圾回收器就不會回收它,若是內存空間不⾜了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使⽤。軟引⽤可⽤來實現內存敏感的⾼速緩存。軟引⽤能夠和⼀個引⽤隊列(ReferenceQueue)聯合使⽤,若是軟引⽤所引⽤的對象被垃圾回收,JAVA虛擬機就會把這個軟引⽤加⼊到與之關聯的引⽤隊列中。

弱引⽤(WeakReference)

  • 若是⼀個對象只具備弱引⽤,那就相似於可有可⽆的⽣活⽤品。弱引⽤與軟引⽤的區別在於:只具備弱引⽤的對象擁有更短暫的⽣命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,⼀旦發現了只具備弱引⽤的對象,無論當前內存空間⾜夠與否,都會回收它的內存。不過,因爲垃圾回收器是⼀個優先級很低的線程, 所以不⼀定會很快發現那些只具備弱引⽤的對象。弱引⽤能夠和⼀個引⽤隊列(ReferenceQueue)聯合使⽤,若是弱引⽤所引⽤的對象被垃圾回收,Java虛擬機就會把這個弱引⽤加⼊到與之關聯的引⽤隊列中。

虛引⽤(PhantomReference)

  • "虛引⽤"顧名思義,就是形同虛設,與其餘⼏種引⽤都不一樣,虛引⽤並不會決定對象的⽣命週期。若是
    ⼀個對象僅持有虛引⽤,那麼它就和沒有任何引⽤⼀樣,在任什麼時候候均可能被垃圾回收。

總結

感謝你看到這裏,文章有什麼不足還請指正!因爲時間關係暫時先整理了這麼多,有什麼不足的能夠私信我,我都會跟進補上,但願這些能在立刻到來的金三銀四里面對你有幫助!安全

另外我還爲你們準備了ava核心知識點+全套架構師學習資料和視頻+一線大廠面試寶典+面試簡歷模板+阿里美團網易騰訊小米愛奇藝快手嗶哩嗶哩面試題+Spring源碼合集+Java架構實戰電子書一塊兒免費分享給你們!數據結構

有須要的能夠關注個人公衆號:前程有光回覆資料便可領取!以爲文章對你有幫助的話記得給我點個贊,天天都會分享java相關技術文章或行業資訊,歡迎你們關注和轉發文章!多線程

相關文章
相關標籤/搜索