1. 程式人生 > >夯實基礎系列一:Java 基礎總結

夯實基礎系列一:Java 基礎總結

前言

大學期間接觸 Java 的時間也不短了,不論學習還是實習,都讓我發覺基礎的重要性。網際網路發展太快了,各種框架各種技術更新迭代的速度非常快,可能你剛好掌握了一門技術的應用,它卻已經走在淘汰的邊緣了。

而學習新技術總要付出一定的時間成本,那麼怎麼降低時間成本呢?那就是打好基礎,技術再怎麼革新,底層的東西也很少會變動,牢固的基礎會幫助你在各種新技術的學習中游刃有餘,快速上手。

因為我選擇的方向是後臺開發,所以談談我認為的基礎有哪些。其他方向肯定也有自己的體系,從低層到高層,可以自己摸索。後臺的話,我覺得網路知識,各種協議,web 知識,資料庫知識,Linux 基本操作以及自己選擇的後臺語言知識,這些是最基礎最需要牢固掌握的。

所以從今天起,會出一系列與後臺基礎相關的博文,一是對自己過去學習的一個總結,二是分享出來,希望可以幫助到需要的人。

概要

Java 基礎我做了 10 個方面的總結,包括基本概念,面向物件,關鍵字,基本型別與運算,字串與陣列,異常處理,Java 平臺與記憶體管理,分散式 Java 應用,多執行緒,IO。以下對這些內容做一些簡單的總結,同時我也有完整的思維導圖,部落格上不方便展示,若有需要,聯絡我

Java 基礎大綱

細節

1. 基本概念

1.1 語言特點
  • 純面向物件
  • 平臺無關性
  • 內建類庫
  • 支援web
  • 安全性
    • 防止程式碼攻擊
  • 健壯性
    • 強型別機制
    • 垃圾回收器
    • 異常處理
    • 安全檢查機制
  • 去除C++中難以理解易混淆的特性
1.2 與C++比較
  • 解釋編譯混合型語言,執行速度慢,跨平臺
  • 純面向物件,只有類,不存在全域性變數或全域性函式
  • 無指標,無多繼承,可多實現
  • 垃圾回收器自動管理記憶體
1.3 main函式知識
  • Java程式入口方法
  • 可由final,synchronized修飾,不能用abstract
1.4 Java程式初始化順序
  • 靜態優於非靜態
  • 父類優於子類
  • 按照成員變數的定義順序
  • 總共10個
1.5 作用域與可見性
  • 靜態變數屬於類
  • 區域性變數屬於花括號
  • 成員變數看下一條
  • public、protected、default、private 可見性依次遞減
1.6 建構函式
  • 與類名相同,無返回值
  • 可過載,不能被繼承,即不能被覆蓋
  • 引數個數任意
  • 伴隨new 一起呼叫,為系統呼叫
  • 完成物件的初始化工作
  • 子類可通過super顯式呼叫父類。父類沒有提供無參,子類必須顯式呼叫
  • 未定義,預設無參,修飾符取決於類修飾符
1.7 標識介面
  • 無任何方法宣告
  • 表示實現它的類屬於一個特定的型別
1.8 clone 方法
  • 實現Cloneable介面
  • 重寫Object類中的clone()
  • clone()中呼叫super.clone()
  • 把淺複製引用指向新的克隆體
1.9 反射
  • 定義:允許程式在執行時進行自我檢查,也允許對其內部成員進行操作
  • 功能
    • 得到一個物件所屬的類
    • 獲取一個類的所有成員和方法
    • 執行時建立物件
    • 在執行時呼叫物件的方法
  • 獲取類的方式
    • class.forName("類路徑")
    • 類名.class
    • 例項.getClass()
1.10 建立物件的四種方式
  • new
  • 反射機制
  • clone()
  • 反序列化
1.11 package 作用
  • 提供多層名稱空間,解決命名衝突
  • 對類按功能進行分類,使專案組織更加清晰

2. 面向物件

2.1 與面向過程區別
  • 層次邏輯關係不同。
    • 面向物件是通過類的層次結構來體現類之間的繼承與發展
    • 面向過程是通過模組的層次結構概括模組與模組間的關係與功能
  • 資料處理方式不同與控制程式方式不同
    • 面向物件是資料與操作封裝成一個整體,通過事件驅動來啟用和執行程式
    • 面向過程是資料單獨儲存,控制程式方式上按照設計呼叫或返回程式
2.2 特性
  • 抽象
  • 繼承
  • 多型
  • 封裝
2.3 這種開發方式優點
  • 開發效率高。程式碼重用
  • 保證軟體的魯棒性。經過長期測試的已有程式碼
  • 保證軟體的高可維護性。設計模式成熟
2.4 繼承
  • 單繼承
  • 只能繼承父類的非私有成員變數和方法
  • 同名成員變數,子類覆蓋,不會繼承
  • 相同函式簽名,子類覆蓋,不會繼承
2.5 組合和繼承區別
  • 組合:在新類中建立原有類的物件。has a
  • 繼承是 is a
2.6 多型
  • 方法過載
    • 編譯時多型
  • 方法覆蓋
    • 執行時多型
  • 成員變數無多型概念
2.7 覆蓋和過載區別
  • 子父類關係,垂直;同類方法間關係,水平
  • 一對方法發生關係;多個方法發生關係
  • 引數列表相同;引數列表不同
  • 呼叫的方法根據物件的型別決定;根據呼叫時的實參表決定方法體
2.8 抽象類與介面異同

  • 不能被例項化
  • 介面的實現類實現了介面,抽象類的子類實現了方法,才能被例項化

  • 介面只能定義方法,不能實現;抽象類可以有定義和實現
  • 介面需要被實現;抽象類需要被繼承
  • 介面強調特定功能的實現;抽象類強調所屬關係
  • 介面成員變數預設為 public static final,成員方法 public abstract
  • 抽象類變數預設default,方法不能用 private、static、synchronized、native 修飾
2.9 內部類
  • 靜態內部類
    • static 修飾
    • 只能訪問外部類中的static資料
  • 成員內部類
    • 與例項繫結
    • 不可定義靜態屬性和方法
    • 外部例項化後,該內部類才能被例項化
  • 區域性內部類
    • 程式碼塊內
    • 不能被public、protected、private以及static修飾
    • 只能訪問final 區域性變數
  • 匿名內部類
    • 無類名
    • 無建構函式,必須繼承或實現其他類
    • 原則
      • 無建構函式
      • 無靜態成員,方法和類
      • 不能是public、protected、private、static
      • 只能建立匿名內部類的一個例項
      • new 後面有繼承或實現
      • 特殊的區域性內部類
2.10 如何獲取父類類名
  • 利用反射:obj.getClass().getSuperClass().getName()
  • 不使用super.getClass()原因:該方法在 Object中為final與native,子類不能覆蓋,返回此Object執行時類
2.11 this
  • 指向當前例項物件
  • 區分成員變數與方法形參
2.12 super
  • 訪問父類成員變數或方法
  • 子類同名會覆蓋,訪問父類只能通過super
  • 子類建構函式需顯示呼叫父類建構函式時,super()必須為建構函式的第一條語句

3. 關鍵字

3.1 變數命名
  • 英文字母
  • 數字
  • _和$
  • 不能包含空白字元
  • 首字元不能為數字
  • 保留字不能做識別符號
  • 區分大小寫
3.2 assert
  • 軟體除錯
  • 執行時開啟 -ea
3.3 static
  • 特定類的統一儲存空間,類繫結
  • 成員變數:屬於類,記憶體中只有一個複製
  • 成員方法:調靜態資料。可實現單例模式
  • 程式碼塊:初始化靜態變數,只被執行一次
  • 內部類:不能與外部類重名,只能訪問外部類靜態資料(包括私有)
3.4 switch
  • 多分支選擇
  • 整型或字元型別變數或整數表示式
  • Java 7 開始支援 String。原理是String的hashCode()返回的int型別值匹配
3.5 volatile
  • 保證執行緒間的可見性
  • 從記憶體中取資料,而不是快取
  • 不保證原子性
3.6 instanceof
  • 二元運算子
  • 判斷一個引用型別的變數所指向的物件是否是一個類的例項
  • 即左邊物件是否是右邊類的例項
3.7 strictfp
  • 精確浮點
  • 確保浮點運算的準確性
  • 若不指定,結果依賴於虛擬機器平臺
  • 指定後依賴於統一標準,保證各平臺的一致性
3.8 null
  • 不是合法的Object例項
  • 無記憶體
  • 表明該引用目前沒有指向任何物件

4. 基本型別與運算

4.1 基本資料型別
  • int長度
    • byte(8 bit)
    • short(16 bit)
    • int(32 bit)
    • long(64 bit)
  • float長度
    • 單精度(32 bit float)
    • 雙精度(64 bit double)
  • boolean 型別變數的取值
    • true
    • false
  • char資料型別:Unicode字元(16 bit)
  • void:java.lang.Void 無法直接對其進行操作
4.2 不可變類
  • 例項建立後,值不可變
  • 所有的基本型別的包裝類+String
  • 優點
    • 使用簡單
    • 執行緒安全
    • 節省記憶體
  • 缺點:會因為值的不同而產生新的物件,導致無法預料的問題
4.3 型別轉換
  • 隱式型別轉換
    • 低精度到高精度
    • byte->short->char->int->long->float->double
  • 顯式型別轉換
    • 反之
    • 可能會損失精度
  • 型別自動轉換
    • 低到高
    • char型別會轉換為其對應的ASCII碼
    • byte、char、short參與運算自動轉為int,但"+=",不轉
    • 基本資料型別與boolean不能相互轉換
    • 多種型別混合運算,自動轉成容量最大型別
  • 運算子優先順序

      點   ()  []
      +(正)    -(負)        ++  --  ~   !
      *   /   %
      +(加)    -(減)
      <<  >>  >>>
      <   <=  >   >=  instanceof
      ==  !=
      &
      |
      ^
      &&
      ||
      ?:
      =   +=  -=  *=  /=  %=  &=       |= ^=  ~=  <<= >>= >>>=

5. 字串與陣列

5.1 字串建立與儲存機制
  • 常量池
  • new String("abc")建立1個或2個物件
5.2 ==、equals和hashCode區別
  • == 比較引用,記憶體
  • 未覆蓋,同==;比較內容
  • hashCode鑑定物件是否相等,返回整數
5.3 String,StringBuffer,StringBuilder
  • String:不可變,執行效率最低
  • StringBuffer:可修改,執行緒安全,效率較高
  • StringBuilder:可修改,執行緒不安全,效率最高
5.4 其他
  • 陣列初始化方式
  • length屬性和length()方法

6. 異常處理

6.1 finally塊執行時機
  • 若try中有return,在return前
  • 若try-finally或catch-finally中都有return,finally會覆蓋
6.2 finally程式碼塊不是一定會被執行
  • 程式進入try之前出現異常
  • try中呼叫System.exit(0)
6.3 Error

嚴重錯誤,不可恢復

6.4 Exception
  • 可恢復,編譯器可捕捉
  • 檢查性異常
    • IO
    • SQL
  • 執行時異常
    • JVM處理
    • NullPointException
    • ClassCastException
    • ArrayIndexOutOfBoundsException
  • 出現異常後,一直往上層拋,直到遇到處理程式碼或最上層
  • 多型。若先捕獲基類,再捕獲子類。子類處理程式碼將永遠不會得到執行

7. Java平臺與記憶體管理

7.1 Java平臺與其他語言平臺的區別
  • 純軟體,包括JVM與JAVA API
  • JVM虛擬,不跨平臺
7.2 JAVA程式碼的執行
  • 程式碼編譯為class:sun jdk 中javac
  • 裝載class:ClassLoader
  • 執行class
    • 解釋執行
    • 編譯執行
      • client compiler
      • server compiler
7.3 java原始碼編譯機制
  • 詞法分析器元件:Token流
  • 語法分析器元件:語法樹
  • 語義分析器元件:註解語法樹
    • 將語法樹中的名字、表示式等元素與變數、方法、型別等聯絡到一起
    • 檢查變數使用前是否已宣告
    • 推導泛型方法的型別引數
    • 檢查型別匹配性
    • 進行常量摺疊
    • 檢查所有語句都可到達
    • 檢查變數的確定性賦值
    • 解除語法糖
    • 將泛型JAVA轉成普通Java
    • 檢查所有checked exception都被捕獲或丟擲
    • 將含語法糖的語法樹轉成簡單語法樹eg:foreach,自動摺疊
  • 程式碼生成器元件:位元組碼
7.4 類載入機制
  • 裝載:全限定名+類載入器載入類
  • 連結
    • 校驗
      • 格式不符,拋VerifyError
      • 載入引用的類失敗:拋NoClassDefFoundError
    • 準備:靜態變數預設初始化
    • 解析:屬性、方法驗證(可選)
  • 初始化(不是類載入必須觸發的)
    • 靜態初始化程式碼
    • 構造器程式碼
    • 靜態屬性初始化
    • 觸發時機
      • 呼叫了new
      • 反射呼叫了類中的方法
      • 子類呼叫了初始化
      • JVM啟動過程中指定的初始化類
        • Bootstrap Class Loader:$JAVA_HOME/jre/lib/rt.jar
        • Extension Class Loader:$JAVA_HOME/jre/lib/ext/*.jar
        • System Class Loader:$CLASSPATH
        • User Defined Class Loader
7.5 類執行機制
  • 解釋執行
    • JVM位元組碼為中間程式碼,由JVM在執行期對其解釋並執行
      • invokestatic
      • invokevirtual
      • invokeinterface
      • invokespecial
    • 基於棧
      • 程式碼緊湊,體積小
      • 執行緒建立後,產生PC和Stack
      • 指令解釋執行
      • 棧頂快取:棧頂值快取在暫存器上
      • 部分棧幀共享
  • 編譯執行
    • client compiler
      • 輕量級,佔記憶體少
      • 方法內聯
      • 去虛擬化
      • 冗餘消除
    • server compiler
      • 重量級,佔記憶體多
      • 逃逸分析是C2進行很多優化的基礎
      • 標量替換:用標量替換聚合量
      • 棧上分配
        • 若物件未逃逸,C2會選擇在棧上直接建立Point物件例項,而不是在堆上
        • 棧上分配更快速,物件易回收
      • 同步消除:如果發現同步的物件未逃逸,那也沒有同步的必要。C2會去掉同步程式碼塊
7.6 記憶體空間
  • 方法區:類資訊,執行緒共享
    • 物件例項+陣列
    • 分代管理
      • 新生代
      • 舊生代
  • 本地方法棧:支援native方法,Sun JDK的實現中本地方法棧和JVM方法棧是同一個
  • PC暫存器:執行緒私有
  • JVM方法棧:執行緒私有
7.7 記憶體分配
  • Java物件,堆上分配,分配需加鎖,開銷大
  • 當堆上空間不足-->GC-->仍不足-->拋OutOfMemory
  • Sun JDK 為新建立的執行緒在Eden上分配TLAB
  • 多個小物件比大物件分配更高效
  • 基於逃逸分析直接從棧上分配
7.8 記憶體回收
  • 收集器
    • 引用計數收集器
      • 計數器增減有消耗
      • 不適合迴圈引用
    • 跟蹤收集器
      • 集中式管理
      • 全域性記錄資料的引用狀態
      • 從根集合掃描物件,可能會造成應用程式暫停
      • 三種實現演算法
        • 複製
          • 適用於回收空間中存活物件較少
          • 缺點:需要增加一塊空的記憶體空間及進行物件的移動
        • 標記-清除:會產生記憶體碎片
        • 標記-壓縮:不產生記憶體碎片
  • Sun JDK中可用GC
    • 新生代
      • 序列GC(Serial GC):複製演算法
        • Minor GC
        • 強軟弱虛
      • 並行回收GC(Parrallel Scavenge):掃描複製多執行緒
      • 並行 GC(ParNew):配合舊生代 CMS
    • 舊生代和持久代可用GC
      • 序列:標記壓縮+清除
      • 並行:標記壓縮
      • 併發:CMS
          1. 標記:暫停
          1. 併發標記:恢復,輪詢著色物件,以標記它們
          1. 重新標記:暫停
          1. 併發收集:恢復
        • CMS記憶體回收易產生碎片,但是它提供了整理碎片的功能
        • 浮動垃圾:CMS回收時產生應該回收但要等到下次CMS才能被回收掉的物件
  • Full GC
    • 對新生代舊生代及持久代都進行的GC
    • 觸發的四種情況
      • 舊生代空間不足
      • 持久代空間滿
      • CMS GC出現promotion failed和concurrent mode failure
      • 統計得到的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間
7.9 記憶體洩露
  • 一個不再被程式使用的物件或變數還在記憶體中佔有儲存空間
  • 符合垃圾回收標準
    • 物件賦空值null
    • 給物件賦予新值,重新分配了記憶體空間
  • 洩露的兩種情況
    • 堆中申請的空間沒有被釋放
    • 物件不再被使用,但仍然存活在記憶體中
  • 洩露原因
    • 靜態集合類
    • 各種連線
    • 監聽器
    • 變數不合理的作用域
    • 單例模式

8. 分散式Java應用

8.1 基於訊息方式實現系統間的通訊
  • TCP/IP+BIO
    • socket.setSoTimeOut()設定等待響應的超時時間
    • 一連線一執行緒
    • 缺點:無論連線是否真實,都要建立執行緒
    • BIO下伺服器端所能支撐的連線數目有限
  • TCP/IP+NIO
    • Channel
      • SocketChannel:建立連線,監聽事件,操作讀寫
      • ServerSocketChannel:監聽埠,監聽連線事件
    • Selector:獲取是否要處理的事件
    • Buffer:存放處理的資料
    • NIO Reactor模式,通過註冊感興趣的事件及掃描是否有感興趣的事件發生,從而做出相應的動作
    • 多個請求,連線複用
    • 只有在有真實的請求時,才會建立執行緒
    • 一請求一執行緒
  • UDP/IP+BIO
    • DatagramSocket:負責監聽埠,讀寫資料
    • DatagramPacket:作為資料流物件進行傳輸
  • UDP/IP+NIO
    • DatagramChannel:監聽埠,進行讀寫
    • ByteBuffer:資料流傳輸
  • NIO好處:只在有流要讀取或可寫入流時才做出相應的IO操作,而不像BIO方式阻塞當前執行緒
8.2 基於遠端呼叫方式實現系統間的通訊
  • 遠端呼叫方式
    • 系統間通訊和系統內一樣
    • 讓使用者感覺呼叫遠端同調用本地一樣
  • 基於Java自身技術
    • RMI:客戶端代理,stub,封裝物件,序列化為流,TCP/IP BIO,Skeleton,反序列化,獲取物件例項,呼叫
    • WebService
        1. 服務端的服務生成WSDL檔案
        1. 將應用+WSDL檔案放入HTTP伺服器
        1. 借用Java輔助工具根據WSDL檔案生成客戶端stub程式碼
        1. stub將產生的物件請求資訊封裝為標準化的SOAP格式資料,併發請求到伺服器端
        1. 服端在接收到SOAP格式資料時進行轉化,反射呼叫相應的Java類
      • SOAP優點支援跨語言,缺點對複雜物件結構難支援
8.3 基於開源框架
  • Spring RMI

9. 多執行緒

9.1 執行緒資源同步機制
  • JVM保證以下操作順序
    • 同一執行緒操作
    • 對於main Memory 上的同一個變數的操作
    • 對於加了鎖的main Memory上的物件操作
  • 為避免資源操作的髒資料問題,JVM提供了
    • synchronized
    • volatile
    • lock/unlock
    • 目的是控制資源競爭
9.2 執行緒互動機制
  • 基於Object的wait/notify/notifyAll
    • 為避免假喚醒,需要double check
    • 呼叫物件的wait-->wait sets--->釋放鎖--->其他執行緒notify---->wait sets---->執行此物件執行緒--->刪除sets中此執行緒
  • 基於JDK 5 併發包,支援執行緒互動
    • Semphore的acquire,release
    • Condition的await,signal
    • CountDownLatch的await和countDown
9.3 執行緒狀態
  • New
  • Runnable
  • Running
  • Wait
  • TimedWait
  • Blocked
  • Terminated
9.4 sleep()與wait()方法的區別
  • sleep
    • 暫停一段時間執行
    • Thread的靜態方法
    • 不釋放鎖
    • 需要捕獲異常
  • wait
    • 使執行緒暫停執行
    • Object方法,用於執行緒間通訊
    • 釋放鎖
9.5 守護執行緒
  • 後臺提供服務
  • 使用者執行緒全部終止,只剩下守護執行緒時,JVM就會退出
  • 呼叫start()之前,呼叫執行緒物件的setDaemon(true)
9.6 join
  • 呼叫該方法的執行緒在執行完run()後,再執行join方法後面的程式碼
  • 執行緒合併,實現同步功能

10. IO

10.1 流本質
  • 資料傳輸
10.2 流分類
  • 位元組流:不使用快取
  • 字元流
    • 碼錶對映
    • 使用快取
10.3 裝飾者模式
  • 執行時動態給物件增加額外的職責
  • 是你還有你,一切拜託你
  • FilterInputStream
10.4 Java Socket
  • ServerSocket server = new ServerSocket(2000);
  • Socker socket = server.accept();
  • 客戶端:Socket socket = new Socket("localhost",2000);
10.5 NIO
  • Channel--Selector--Buffer
  • 反應器模式
10.6 序列化
  • 物件持久化方式
  • 解決在對物件流進行讀寫操作時引發的問題
  • 物件寫進流裡進行網路傳輸,儲存到檔案,資料庫
10.7 如何實現序列化
  • 實現Serializable介面
  • 使用FileOutputStream來構造ObjectOutputStream物件
  • 使用該物件的writeObject(obj)方法將物件寫出
  • 要恢復時,使用對應的輸入流
10.8 序列化特點
  • 一個類能被序列化,它的子類也能被序列化
  • static代表類成員,transient代表臨時資料。均不能被序列化
  • 序列化影響效能,需要才使用
  • 需要通過網路來發送物件,或物件的狀態需要被持久化到資料庫或檔案中
  • 序列化能實現深複製,即可以複製引用的物件
10.9 反序列化
  • 將流轉化為物件
  • UID最好自己定義。優點
    • 提高程式執行效率。省去計算過程
    • 提高程式不同平臺相容性。不同計算方式,反序列化失敗
    • 增強程式各個版本的可相容性。加入新屬性,預設UID變化
10.10 外部序列化
  • 實現Externalizable介面控制