Java基礎總結

Java基礎


面向對象的特性

  • 封裝,將程序實現的細節隱藏起來,公開的方法顯示對象的功能。
  • 繼承,子類繼承父類後,具有父類的功能和屬性,避免代碼重複。
  • 多態,父類可以聲明子類,運行時依然保持子類的特徵。

Java與C++的區別

1 Java是解釋型語言,一次編譯到處運行,Java首先需要將代碼編譯爲字節碼文件,之後由虛擬機解釋執行,C++爲編譯型語言,則編譯時將代碼編譯爲機器指令,機器可以直接運行效率高但是不能跨平臺。

2 Java不具有指針的概念,由虛擬機負責管理內存,消除了野指針帶來的影響,C++可以使用指針操作內存,程序運行有風險。

3 Java不需要程序員釋放內存,釋放內存的操作由虛擬機的垃圾回收來完成,C++需要在使用完對象後析構函數釋放內存。

4 Java不支持多繼承,但提供了接口,可以實現多個接口,C++支持多繼承的語法。

初始化順序

Java的類加載過程決定了初始化的順序,靜態對象或者代碼加載過一次之後就不再進行加載,如果類未曾被虛擬機加載過,則按照以下順序加載:

1 父類的靜態對象和靜態代碼

2 子類的靜態對象和靜態代碼

3 父類的非靜態對象和代碼

4 父類的構造器

5 子類的非靜態對象和代碼

6 子類的構造器

權限訪問控制

Java中採用了4個關鍵字進行類、方法、變量的權限控制,分別爲:

  • public 可以被所有類訪問
  • protected 同一個包下的類或者不同包下的子類
  • default 在同一個包下的類訪問
  • private 只能在同一個類中訪問

深複製、淺複製

  • 淺複製只會複製對象的基本數據類型,對象如果存在引用的話只複製地址,當拷貝的對象改變引用中的基本數據類型時,被拷貝的對象的基本數據類型也會變化。
  • 深複製需要將基本數據類型和引用類型中的所有數據均複製,兩個對象進行任何操作時不會相互影響。

反射機制

通過class.forname()可以獲取其他對象的類信息、方法信息以及變量信息,通過反射可以創建類的對象,調用對象方法等操作。

多態

多態分爲編譯時多態和運行時多態,分別通過重載和重寫實現的,重載在同一個類中實現,同一個方法可以具有不用的參數類型或者個數,而重寫指的是子類對父類重寫,子類可以獲取父類的方法和屬性,父類聲明的子類對象在編譯時爲父類類型,但在運行時爲調用子類的方法。

抽象和接口

  • 抽象可以有自己的普通方法,而且可以聲明權限,接口只能包括抽象方法,子類在繼承抽象類或者實現接口時都需要實現抽象方法。
  • 抽象中的變量權限範圍更加廣泛,接口中只能爲public final static類型的變量,在之後的版本中加入了default控制。
  • 一個類只能繼承一個抽象類,但可以實現多個接口。
  • 在設計理念上,接口反應的是like a的關係,而抽象指的是is a的關係。

內部類

內部類主要包括四種,分別爲靜態內部類,非靜態內部類,局部內部類,匿名類。

this super

this用來指代當前類的對象實例,super可以調用父類的方法。分別可以用於重載和重寫中。

final

final可以用來修飾成員變量,表示該變量不可修改,修飾成員方法則代表該方法不可以被重寫,修飾類則表明該類不能被繼承。

instanceof

instanceof是一個運算符,不是關鍵字,用於判斷前者實例是否爲後者類的子類對象。

基本數據類型

基本數據類型包括char、byte、short、int、double、float、long、boolean八種類型

基本類型 所佔字節 範圍
byte 1 -2^7~2*7-1
char 2 0~2^16-1
short 2 -2^15~2*15-1
int 4 -2^31~2*31-1
float 4 32位單精度
double 8 64位雙精度
long 8 -2^63~2*63-1

自動裝箱

自動裝箱是Java引入的語法糖,方便了引用與基本類型的轉換操作,可以將基本數據直接賦值給該數據類型的包裝類,即完成了自動裝箱操作,反之,也可以將包裝類型的數據賦值給基本類型的變量,即完成了拆箱操作。由於裝箱過程的底層實現原因,Integer範圍在[-128-127]的數值,不會創建新的對象,此範圍的的數值比較時返回爲true,而此範圍之外的數值比較返回值爲false。

類型轉換

類型轉換主要分爲兩種,自動類型轉換和強制類型轉換

範圍低的數據類型向範圍高的數據類型轉換時,發生自動類型轉換,未補滿的位置爲0

範圍高的數據類型向範圍低的數據類型轉換時,發生強制類型轉換,多餘的位強制丟棄

編碼方式

Java的編碼方式爲Unicode,每個字符佔有2個字節,範圍爲0-2*16-1,String是由char組成的,但是中英文所佔的字節不相同,中文佔用兩個字節,英文佔用一個字節。

euqals和hashcode

equals和hashcode都是Object類的默認方法,它們都是用來比較兩個類是否相同,兩個對象equals方法返回值爲true時,hashcode返回值也一定爲true,但是如果hashcode方法返回爲true時,equals方法返回值不一定爲true。hashcode()方法主要用於解決Java中的集合問題,向一個集合中添加元素時,判斷其中是否已經有一個同樣的值如果用equals方法遍歷耗費時間,所以採用hash結構存儲數據,可以減少查詢時間。

當重寫equals方法時,同時也需要重寫hashcode方法。

String StringBuffer StringBuilder

String是不可變類,當對象被創建後,字符串的值不能再改變。

StringBuffer是可變類,用於多線程下操作大量數據。

StringBuilder也是可變類,用於單線程下操作大量數據。

Error和Exception

異常主要分爲檢查型異常和非檢查型異常,檢查型異常在編譯器階段就會檢測出來,而非檢查型異常需要等到程序運行時才能檢測,主要分爲Error和Exception,Error是系統錯誤包括內存溢出,棧溢出等,程序無法控制,而Exception是程序可以控制的,出現異常時可能爲數組越界異常、空指針異常、參數類型錯誤異常、運算錯誤異常等。

字節流和字符流

文件傳輸時可以採用兩種方式傳輸,以字節的方式傳遞,主要繼承InputStream和OutputStream,以字符的方式傳遞,主要繼承Reader和Writer。

NIO BIO AIO

BIO是同步阻塞的IO,一個線程需要請求數據時,如果數據未能及時返回,則一直處於等待狀態。
NIO是同步非阻塞的,一個線程需要請求數據時,如果數據未能及時返回,則會將現在的狀態返回該線程,線程則不斷髮出請求直到返回數據。
BIO是異步非阻塞的,當一個線程請求數據時,可以先完成其他的任務,當數據返回時,發送給線程數據返回完成的狀態。

NIO操作面向緩衝區,數據從Channel讀取到Buffer緩衝區,隨後在Buffer中處理數據。NIO主要包括三個組件:

  • buffer,當寫入數據到buffer中時,buffer會記錄已經寫入的數據大小。當需要讀數據時,通過flip()方法把buffer從寫模式調整爲讀模式;在讀模式下,可以讀取所有已經寫入的數據。當讀取完數據後,需要清空buffer,以滿足後續寫入操作。
  • channel,提供map()方法可以將文件映射到內存也就是buffer中,通道可以進行讀和寫,也可以進行異步操作,通道不與程序直接交互,而是通過buffer進行傳遞。
  • selector,用於檢查一個或多個NIO Channel的狀態是否處於可讀、可寫。

序列化

爲了使創建的Java對象保存在文件或者進行網絡傳輸,需要對其進行序列化處理,需要該類實現Serializable和Externalizable兩個接口之一。反序列化則是將保存的二進制文件轉化爲對象的操作。

ArrayList和LinkedList

ArrayList是基於數組實現的,默認數組大小爲10,當數組已滿時,擴展數組大小爲原來的1.5倍,按下標訪問或設置數組元素時效率很高,當按下標插入或者刪除元素時,則由於對齊原因,需要移動部分元素的位置。LinkedList則是基於鏈表實現的,方便插入和刪除元素,但是讀取元素使需要遍歷整個鏈表,用時較長,但是由於本身採用鏈表實現,沒有容量限制。

HashMap和TreeMap

HashMap採用hash的方法解決衝突問題,它是基於數組和鏈表實現的,當插入一個元素時,首先計算該元素的hash值,如何在數組中沒有衝突,則將此元素插入到該位置,如果在數組中有衝突,則需要在該衝突點的鏈表中查找是否有相同的元素,如果沒有,則在鏈表中插入新值,如果有相同元素,則新值不能插入,當插入新值時,map的容量已經達到臨界條件時,即容量*負載因子,需要進行擴容操作,將容量擴展爲原來的2倍,重新計算每個元素的hash值,完成元素的重新劃分。

TreeMap在插入新的元素時,會對其進行排序操作,當遍歷TreeMap時,得到的序列是有序的。

LinkedHashMap與HashMap不同的是,它是按照數據的插入順序存儲的,當遍歷LinkedHashMap存儲的元素時,得到的結果與插入時的順序一致。

創建對象

創建對象主要發生在以下的幾種情況下:

1 最常用的新建一個對象
2 實現clone方法實現對象克隆
3 序列化一個對象,之後反序列
4 反射方法創建對象

內存劃分

JVM負責內存的劃分,主要包括程序計數器、虛擬機棧、虛擬機堆、方法區等部分。

程序計數器,記錄當前正在執行指令的行號,是線程私有的。

虛擬機棧,是方法的運行空間,局部變量都存儲在棧中,當方法運行結束後,虛擬機棧重新置爲空,是線程私有的。

虛擬機堆,Java創建的對象都存在堆中,引用存在棧中,引用指向堆中的地址,是線程共享的。

方法區,用於存儲類加載的信息,是線程共享的。

常量池,是方法區的一部分,用於存儲符號引用以及字符串信息,是線程公有的。

垃圾回收

垃圾回收是Java特有的內存回收機制,Java創建對象後會佔用大量的內存,在對象不再使用後需要將該內存區域釋放,判斷對象是否還需使用主要採用了引用計數法和可達性分析。

引用計數法指的是每個對象在創建後會有一個引用指向堆中的位置,當引用被改變或者達到生命週期時,引用變量-1,當有一個新的引用指向該實例後,該實例的引用變量+1,當引用變量爲0時,就可以釋放該區域了,引用計數法存在的問題是如果有兩個對象中的變量互相指向對方,則無法釋放兩個對象的內存。

可達性分析算法是指建立一個根節點,其他對象實例的節點都指向根節點,當某個實例與根節點不再相連時,即可以釋放該實例內存區域。

常用垃圾回收算法主要包括三種,標記清理算法、複製算法和標記整理算法。

  • 標記清理算法指的是當內存佔用空間已滿時,清理需要釋放的內存區域,不能釋放的區域位置不變。
  • 複製算法指的是將內存區域分爲兩個部分,當其中部分已滿時,將不能釋放的區域複製在另外半邊,之前半邊的內存區域全部清空。
  • 標記整理算法指的是當內存佔有空間已滿時,清理需要釋放的內存區域,將不能釋放的區域移至內存區域的一邊對齊。

另外根據對象的生存時間不同,將其分爲新生代和老生代,新生代又被分爲Eden和Surviver區,新生代按照複製算法清理垃圾,老生代按照標記清理或標記整理算法回收內存。當新建一個對象實例後,首先在Eden區分配空間,當Eden空間已滿並且該對象實例不需要清理,則將此實例轉入Surviver區,如果在該區經過多次GC後依然存在,則將其轉入老年代。

類加載

類的加載是由類加載器完成的,類加載器分爲根加載器、擴展類加載器、自定義類加載器,當一個類需要加載時,按照以上順序依次加載,類加載器完成的工作包括加載、連接和初始化,其中連接包括驗證、準備和解析。

  • 加載,裝載二進制文件
  • 驗證,驗證class文件是否符合要求
  • 準備,爲類變量分配空間,在方法區完成
  • 解析,將符號引用轉化爲直接引用
  • 初始化,調用類加載器完成類的初始化

類的初始化發生情況如下所示:

  • 新建一個對象
  • 獲取或重置類靜態變量
  • 調用類的靜態方法
  • 反射方式創建對象
  • 子類初始化前對父類初始化
發佈了67 篇原創文章 · 獲贊 32 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章