兩萬字《Java完全自學手冊》15張導圖,100本電子書,送給所有的零基礎小白(建議收藏)

2021-10-18 12:00:03

直接跳轉到末尾獲取福利

  • 15張學習路線導圖

  • 3G學習資料

  • 10G計算機電子書

哈嘍,大家好,我是一條~

Java學習如逆水行舟,不進則退。一條一路自學過來,踩過很多坑,吃過很多苦。

現在回想起來,當初要是能有一個完整的學習路線讓我按圖索驥就好了。

思來想去,決定總結一份學習路線來幫助正在路上或者準備出發的Java新手。

獲取路線

該路線圖右側為主路線,需循序漸進,步步為營;左側為輔助路線,需貫穿始終,熟練掌握。

建議做好時間規劃,不斷的提高自己的學習效率,學習過程中儘量把手機調至靜音給自己一個安靜的學習環境和氛圍。

同時,巧婦難為無米之炊,一條學習新知識的一般方法為先看視訊學基礎,再看書學原理,最後看部落格查缺補漏,沉澱消化。

考慮到實體書都特別貴,特為每個章節都準備了電子書,共10G。獲取

最後,說一下這麼多年學習java的一些心得,希望能幫助到大家。

java基礎

學習任何語言,都是先從他的基本語法開始,如果你有C語言的基礎,會容易許多,沒有也不用現學。

image-20211011130649245

基本資料型別

Java 語言提供了 8 種基本型別,大致分為 4 類(8位元=1位元組)

  • 整數型
    • byte - 1位元組
    • short - 2位元組
    • int - 4位元組
    • long - 8位元組,賦值時一般在數位後加上 lL
  • 浮點型
    • float - 4位元組,直接賦值時必須在數位後加上 fF
    • double - 8位元組,賦值時一般在數位後加 dD
  • 字元型
    • char - 2位元組,儲存 Unicode 碼,用單引號賦值
  • 布林型
    • boolean - 1位元組,只有 true 和 false 兩個取值,一個位元組就夠了

參照資料型別

簡單來說,所有的非基本資料型別都是參照資料型別,除了基本資料型別對應的參照型別外,類、 介面型別、 陣列型別、 列舉型別、 註解型別、 字串型都屬於參照型別。

主要有以下區別:

1、儲存位置

  • 基本變數型別在方法中定義的非全域性基本資料型別變數的具體內容是儲存在棧中的
  • 參照資料型別變數其具體內容都是存放在堆中的,而棧中存放的是其具體內容所在記憶體的地址

2、傳遞方式

  • 基本資料型別是按值傳遞
  • 參照資料型別是按參照傳遞

存取修飾符

存取修飾符就是限制變數的存取許可權的。

比如你有個「賺錢」的方法,誰都不想給用,那就把方法設成private(私有);

後來你有了老婆孩子,你想讓他們也會賺錢,就得設定成default(同一個包);

後來你又有了第二個孩子,但你發現他不會賺錢的方法,為啥呢?因為你被了(default不支援不同包的子類);

可為了大局,你還是選擇接受這個孩子,悄悄把方法設定成了proteced(保護子類,即使不同包);

後來你老了,明白了開源才是共贏,就設定成了public(公有的);

不知道你聽懂了嗎,估計看到被那啥了就不想看了吧,沒關係,看圖(也是綠的)

image-20210805183734693

static關鍵字

主要意義:

我日常呼叫方法都是物件.方法,static的主要意義就是可以建立獨立於具體物件的域變數或者方法。也就是實現即使沒有建立物件,也能使用屬性和呼叫方法!

另一個比較關鍵的作用就是 用來形成靜態程式碼塊以優化程式效能static塊可以置於類中的任何地方,可以有多個。在類初次被載入的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次,可以用來優化程式效能

通俗理解:

static是一個可以讓你升級的關鍵字,被static修飾,你就不再是你了。

final關鍵字

final翻譯成中文是「不可更改的,最終的」,顧名思義,他的功能就是不能再修改,不能再繼承。我們常見的String類就是被final修飾的。

將類、方法、變數宣告為final能夠提高效能,這樣JVM就有機會進行估計,然後優化。

按照Java程式碼慣例,final變數就是常數,而且通常常數名要大寫:

  • final關鍵字可以用於成員變數、本地變數、方法以及類。
  • final成員變數必須在宣告的時候初始化或者在構造器中初始化,否則就會報編譯錯誤。
  • 不能夠對final變數再次賦值。
  • final方法不能被重寫。
  • final類不能被繼承。
  • 介面中宣告的所有變數本身是final的。
  • final和abstract這兩個關鍵字是反相關的,final類就不可能是abstract的。

物件導向三大特性

封裝

1.什麼是封裝

封裝又叫隱藏實現。就是隻公開程式碼單元的對外介面,而隱藏其具體實現。

其實生活中處處都是封裝,手機,電腦,電視這些都是封裝。你只需要知道如何去操作他們,並不需要知道他們裡面是怎麼構造的,怎麼實現這個功能的。

2.如何實現封裝

在程式設計裡,封裝往往是通過存取控制實現的。也就是剛才提到的存取修飾符。

3.封裝的意義

封裝提高了程式碼的安全性,使程式碼的修改變的更加容易,程式碼以一個個獨立的單元存在,高內聚,低耦合。

好比只要你手機的充電介面不變,無論以後手機怎麼更新,你依然可以用同樣的傳輸線充電或者與其他裝置連線。

封裝的設計使使整個軟體開發複雜度大大降低。我只需要使用別人的類,而不必關心其內部邏輯是如何實現的。我能很容易學會使用別人寫好的程式碼,這就讓軟體協同開發的難度大大降低。

封裝還避免了命名衝突的問題。

好比你家裡有各種各樣的遙控器,但比還是直到哪個是電視的,哪個是空調的。因為一個屬於電視類一個屬於空調類。不同的類中可以有相同名稱的方法和屬性,但不會混淆。

繼承

繼承的主要思想就是將子類的物件作為父類別的物件來使用。比如王者榮耀的英雄作為父類別,後裔作為子類。後裔有所有英雄共有的屬性,同時也有自己獨特的技能。

多型

多型的定義:

指允許不同類的物件對同一訊息做出響應。即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式。(傳送訊息就是函數呼叫)

簡單來說,同樣呼叫攻擊這個方法,後裔的普攻和亞瑟的普攻是不一樣的。

多型的條件:

  • 要有繼承
  • 要有重寫
  • 父類別參照指向子類物件

多型的好處:

多型對已存在程式碼具有可替換性。

多型對程式碼具有可擴充性。

它在應用中體現了靈活多樣的操作,提高了使用效率。

多型簡化對應用軟體的程式碼編寫和修改過程,尤其在處理大量物件的運算和操作時,這個特點尤為突出和重要。

Java中多型的實現方式:

  • 介面實現
  • 繼承父類別進行方法重寫
  • 同一個類中進行方法過載

完整講解

Java基礎完整講解

入門練習案例

入門練習100例

JavaWeb

JavaWeb是用Java技術來解決相關web網際網路領域的技術棧。Web就是網頁,分為靜態和動態。涉及 的知識點主要包括jsp,servlet,tomcat,http,MVC等知識。

本章難度不高,但也不可忽視。其中前端基礎不需花過多時間,重點放在Tomcat上,會陪伴你整個Java生涯。

HTTP網路請求方式

  • GET:最常用的方式,用來向伺服器請求資料,沒有請求體,請求引數放在URL後面。
  • POST:用於向表單提交資料,傳送的資料放在請求體中。
  • PUT:用來向伺服器上傳檔案,一般對應修改操作,POST用於向伺服器傳送資料,PUT用於向伺服器儲存資料。沒有驗證機制,任何人都可以操作,存在安全問題。具有冪等性。
  • DELETE:用於刪除伺服器上的檔案,具有冪等性。同樣存在安全問題。
  • HEAD:用HEAD進行請求伺服器時,伺服器只返回響應頭,不返回響應體。與GET一樣沒有請求體,常用於檢查請求的URL是否有效。
  • PATCH:對資源進行部分修改。與PUT區別在於,PUT是修改所有資源,替代它,而PATCH只是修改部分資源。
  • TRACE:用來檢視一個請求,經過閘道器,代理到達伺服器,最後請求的變換。因安全問題被禁用。
  • OPTIONS:當用戶端不清楚對資源操作的方法,可以使用這個,具有冪等性。

GET和POST

  1. 作用不同:GET 用於獲取資源,而 POST 用於傳輸實體主體。
  2. 引數位置不一樣: GET 的引數是以查詢字串出現在 URL 中,而 POST 的引數儲存在實體主體中。雖然GET的引數暴露在外面,但可以通過加密的方式處理,而 POST 引數即使儲存在實體主體中,我們也可以通過一些抓包工具如(Fiddler)檢視。
  3. 冪等性:GET是冪等性,而POST不是冪等性。(面試官緊接著可能就會問你什麼是冪等性?如何保證冪等性?)
  4. 安全性:安全的 HTTP 方法不會改變伺服器狀態,也就是說它只是可讀的。 GET 方法是安全的,而 POST 卻不是,因為 POST 的目的是傳送實體主體內容,這個內容可能是使用者上傳的表單資料,上傳成功之後,伺服器可能把這個資料儲存到資料庫中,因此狀態也就發生了改變。

冪等性

是否具有冪等性也是一個http請求的重要關注點。

冪等性:指的是同樣的請求不管執行多少次,效果都是一樣,伺服器狀態也是一樣的。具有冪等性的請求方法沒有副作用。(統計用途除外)

如何保證冪等性

假設這樣一個場景:有時我們在填寫某些form表單時,儲存按鈕不小心快速點了兩次,表中竟然產生了兩條重複的資料,只是id不一樣。

這是一個比較常見的冪等性問題,在高並行場景下會變得更加複雜,那怎麼保證介面的冪等性呢?

1.insert前select

插入資料前先根據某一欄位查詢一下資料庫,如果已經存在就修改,不存在再插入。

2.加鎖

加鎖可解決一切問題,但也要考慮並行性。

主要包括悲觀鎖,樂觀鎖,分散式鎖。

悲觀鎖的並行性較低,更適合使用在防止資料重複的場景,注意冪等性不光是防止重複還需要結果相同。

樂觀鎖可以很高的提升效能,也就是常說的版本號。

分散式鎖應用在高並行場景,主要用redis來實現。

3.唯一索引

通過資料庫的唯一索引來保證結果的一致性和資料的不重複。

4.Token

兩次請求,第一請求拿到token,第二次帶著token去完成業務請求。

常見的網路狀態碼

網路狀態碼共三位數位組成,根據第一個數位可分為以下幾個系列:

1xx(資訊性狀態碼)

代表請求已被接受,需要繼續處理。

包括:100、101、102

這一系列的在實際開發中基本不會遇到,可以略過。

2xx(成功狀態碼)

表示成功處理了請求的狀態程式碼。

200:請求成功,表明伺服器成功了處理請求。

202:伺服器已接受請求,但尚未處理。

204:伺服器成功處理了請求,但沒有返回任何內容。

206:伺服器成功處理了部分 GET 請求。

3xx(重定向狀態碼)

300:針對請求,伺服器可執行多種操作。

301:永久重定向

302:臨時性重定向

303:303與302狀態碼有著相同的功能,但303狀態碼明確表示使用者端應當採用GET方法獲取資源。

301和302的區別?

301比較常用的場景是使用域名跳轉。比如,我們存取 http://www.baidu.com 會跳轉到https://www.baidu.com,傳送請求之後,就會返回301狀態碼,然後返回一個location,提示新的地址,瀏覽器就會拿著這個新的地址去存取。

302用來做臨時跳轉比如未登陸的使用者存取使用者中心重定向到登入頁面。

4xx(使用者端錯誤狀態碼)

400:該狀態碼錶示請求報文中存在語法錯誤。但瀏覽器會像200 OK一樣對待該狀態碼。

401:表示傳送的請求需要有通過HTTP認證的認證資訊。比如token失效就會出現這個問題。

403:被拒絕,表明對請求資源的存取被伺服器拒絕了。

404:找不到,表明伺服器上無法找到請求的資源,也可能是拒絕請求但不想說明理由。

5xx(伺服器錯誤狀態碼)

500:伺服器本身發生錯誤,可能是Web應用存在的bug或某些臨時的故障。

502:該狀態碼錶明伺服器暫時處於超負載或正在進行停機維護,現在無法處理請求。

⚠️有時候返回的狀態碼響應是錯誤的,比如Web應用程式內部發生錯誤,狀態碼依然返回200

轉發和重定向

上面提到了重定向,那你知道什麼是轉發嗎?

1.轉發

A找B借錢,B沒有錢,B去問C,C有錢,C把錢借給A的過程。

客戶瀏覽器傳送http請求,web伺服器接受此請求,呼叫內部的一個方法在容器內部完成請求處理和轉發動作,將目標資源傳送給客戶。

整個轉發一個請求,一個響應,位址列不會發生變化,不能跨域存取。

2.重定向

A找B借錢,B沒有錢,B讓A去找C,A又和C借錢,C有錢,C把錢借給A的過程。

客戶瀏覽器傳送http請求,web伺服器接受後傳送302狀態碼響應及對應新的location給客戶瀏覽器,客戶瀏覽器發現是302響應,則自動再傳送一個新的http請求,請求url是新的location地址,伺服器根據此請求尋找資源並行送給客戶。

兩個請求,兩個響應,可以跨域。

Servlet

servlet是一個比較抽獎的概念,也是web部分的核心元件,大家回答這個問題一定要加入自己的理解,不要背定義。

servlet其實就是一個java程式,他主要是用來解決動態頁面的問題。

之前都是瀏覽器像伺服器請求資源,伺服器(tomcat)返回頁面,但使用者多了之後,每個使用者希望帶到不用的資源。這時就該servlet上場表演了。

servlet存在於tomcat之中,用來網路請求與響應,但他的重心更在於業務處理,我們存取京東和淘寶的返回的商品是不一樣的,就需要程式設計師去編寫,目前MVC三層架構,我們都是在service層處理業務,但這其實是從servlet中抽取出來的。

看一下servlet處理請求的過程:

image-20210812201447743

Servlet的生命週期

Servlet生命週期分為三個階段:

  • 初始化階段 呼叫init()方法
  • 響應客戶請求階段  呼叫service()方法-àdoGet/doPost()
  • 終止階段  呼叫destroy()方法

session、cookie、token

首先我們要明白HTTP是一種無狀態協定,怎麼理解呢?很簡單

夏洛:大爺,樓上322住的是馬冬梅家吧?
大爺:馬冬什麼? 
夏洛:馬冬梅。 
大爺:什麼冬梅啊? 
夏洛:馬冬梅啊。 
大爺:馬什麼梅?
夏洛:行,大爺你先涼快著吧。

這段對話都熟悉吧,HTTP就是那個大爺,那如果我們就直接把「大爺」放給使用者,使用者不用幹別的了,就不停的登入就行了。

既然「大爺不靠譜」,我們找「大娘」去吧。

哈哈哈,開個玩笑,言歸正傳。

為了解決使用者頻繁登入的問題,在伺服器端和使用者端共同維護一個狀態——對談,就是所謂session,我們根據對談id判斷是否是同一使用者,這樣使用者就開心了。

但是伺服器可不開心了,因為使用者越來越多,都要把session存在伺服器,這對伺服器來說是一個巨大的開銷,這是伺服器就找來了自己的兄弟幫他分擔(叢集部署,負載均衡)。

但是問題依然存在,如果兄弟掛了怎麼辦,兄弟們之間的資料怎麼同步,使用者1把session存放在機器A上,下次存取時負載均衡到了機器B,完了,找不到,使用者又要罵娘。

這時有人思考,為什麼一定要伺服器端儲存呢,讓使用者端自己儲存不就好了,所以就誕生了cookie,下一次請求時客戶段把cookie傳送給伺服器,說我已經登入了。

但是空口無憑,伺服器怎麼知道哪個cookie是我發過去的呢?如何驗證成了新的問題。

有人想到了一個辦法,用加密令牌,也就是token,伺服器發給使用者端一個令牌,令牌儲存加密後id和金鑰,下一次請求時通過headers傳給伺服器端,由於金鑰別人不知道,只有伺服器端知道,就實現了驗證,且別人無法偽造。

MVC與三層架構

三層架構與MVC的目標一致:都是為了解耦和、提高程式碼複用。MVC是一種設計模式,而三層架構是一種軟體架構。

MVC

Model 模型

模型負責各個功能的實現(如登入、增加、刪除功能),用JavaBean實現。

View 檢視

使用者看到的頁面和與使用者的互動。包含各種表單。 實現檢視用到的技術有html/css/jsp/js等前端技術。

常用的web 容器和開發工具

Controller 控制器

控制器負責將檢視與模型一一對應起來。相當於一個模型分發器。接收請求,並將該請求跳轉(轉發,重定向)到模型進行處理。模型處理完畢後,再通過控制器,返回給檢視中的請求處。

三層架構

表現層(UI)(web層)、業務邏輯層(BLL)(service層)、資料存取層(DAL)(dao層) ,再加上實體類庫(Model)

  • 實體類庫(Model),在Java中,往往將其稱為Entity實體類。資料庫中用於存放資料,而我們通常選擇會用一個專門的類來抽象出資料表的結構,類的屬性就一對一的對應這表的屬性。一般來說,Model實體類庫層需要被DAL層,BIL層和UI層參照。
  • 資料存取層(DAL),主要是存放對資料類的存取,即對資料庫的新增、刪除、修改、更新等基本操作,DAL就是根據業務需求,構造SQL語句,構造引數,呼叫幫助類,獲取結果,DAL層被BIL層呼叫
  • 業務邏輯層(BLL),BLL層好比是橋樑,將UI表示層與DAL資料存取層之間聯絡起來。所要負責的,就是處理涉及業務邏輯相關的問題,比如在呼叫存取資料庫之前,先處理資料、判斷資料。

完整講解

JavaWeb完整講解

集合

工欲善其事必先利其器,集合就是我們的器。

ArrayList

底層實現

由什麼組成,我說了不算,看原始碼。怎麼看呢?

List<Object> list = new ArrayList<>();

新建一個ArrayList,按住ctrlcommand用滑鼠點選。

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     * 翻譯
     * 陣列緩衝區,ArrayList的元素被儲存在其中。ArrayList的容量是這個陣列緩衝區的長度。
     * 任何空的ArrayList,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,
     * 當第一個元素被新增時,將被擴充套件到DEFAULT_CAPACITY。
     */
    transient Object[] elementData; 

毋庸置疑,底層由陣列組成,那陣列的特點就是ArrayList的特點。

  • 由於陣列以一塊連續的記憶體空間,每一個元素都有對應的下標,查詢時間複雜度為O(1)。好比你去住酒店,每個房間都挨著,房門都寫著房間號。你想找哪一間房是不是很容易。
  • 相對的,一塊連續的記憶體空間你想打破他就沒那麼容易,牽一髮而動全身,所以新增和刪除的時間複雜度為O(n),想像你在做excel表格的時候,想增加一列,後面的列是不是都要跟著移動。
  • 元素有序,可重複。可用在大多數的場景,這個就不需要過多解釋了。

擴容

我們知道陣列是容量不可變的資料結構,隨著元素不斷增加,必然要擴容。

所以擴容機制也是集合中非常容易愛問的問題,在原始碼中都可以一探究竟。

1.初始化容量為10,也可以指定容量建立。

    /**
     * Default initial capacity.
     * 定義初始化容量
     */
    private static final int DEFAULT_CAPACITY = 10;

2.陣列進行擴容時,是將舊資料拷貝到新的陣列中,新陣列容量是原容量的1.5倍。(這裡用位運算是為了提高運算速度)

private void grow(int minCapacity) {
  int newCapacity = oldCapacity + (oldCapacity >> 1);
}

3.擴容代價是很高得,因此再實際使用時,我們因該避免陣列容量得擴張。儘可能避免資料容量得擴張。儘可能,就至指定容量,避免陣列擴容的發生。

為什麼擴容是1.5倍?

  • 如果大於1.5,也就是每次擴容很多倍,但其實我就差一個元素的空間,造成了空間浪費。
  • 如果小於1.5,擴容的意義就不大了,就會帶來頻繁擴容的問題。

所以,1.5是均衡了空間佔用和擴容次數考慮的。

執行緒安全問題

怎麼看執行緒安全?說實話我以前都不知道,看網上說安全就安全,說不安全就不安全。

其實都在原始碼裡。找到增加元素的方法,看看有沒有加鎖就知道了。

    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

沒有加鎖,所以執行緒不安全

在多執行緒的情況下,插入資料的時可能會造成資料丟失,一個執行緒在遍歷,另一個執行緒修改,會報ConcurrentModificationException(並行修改異常)錯誤.

多執行緒下使用怎麼保證執行緒安全?

保證執行緒安全的思路很簡單就是加鎖,但是你可沒辦法修改原始碼去加個鎖,但是你想想編寫java的大佬會想不到執行緒安全問題?

早就給你準備了執行緒安全的類。

1.Vector

Vector是一個執行緒安全的List類,通過對所有操作都加上synchronized關鍵字實現。

找到add方法,可以看到被synchronized關鍵字修飾,也就是加鎖,但synchronized是重度鎖,並行性太低,所以實際一般不使用,隨著java版本的更新,慢慢廢棄。

public void add(E e) {
            int i = cursor;
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.add(i, e);
                expectedModCount = modCount;
            }
            cursor = i + 1;
            lastRet = -1;
        }

2.Collections

注意是Collections而不是Collection

Collections位於java.util包下,是集合類的工具類,提供了很多操作集合類的方法。其中Collections.synchronizedList(list)可以提供一個執行緒安全的List

對於Map、Set也有對應的方法

3.CopyOnWrite(寫時複製)

寫時複製,簡稱COW,是計算機程式設計領域中的一種通用優化策略。

當有多人同時存取同一資源時,他們會共同獲取指向相同的資源的指標,供存取者進行讀操作。

當某個呼叫者修改資源內容時,系統會真正複製一份副本給該呼叫者,而其他呼叫者所見到的最初的資源仍然保持不變。修改完成後,再把新的資料寫回去。

通俗易懂的講,假設現在有一份班級名單,但有幾個同學還沒有填好,這時老師把檔案通過微信傳送過去讓同學們填寫(複製一份),但不需要修改的同學此時檢視的還是舊的名單,直到有同學修改好發給老師,老師用新的名單替換舊的名單,全班同學才能檢視新的名單。

共用讀,分開寫。讀寫分離,寫時複製。

在java中,通過CopyOnWriteArrayListCopyOnWriteArraySet容器實現了 COW 思想。

平時查詢的時候,都不需要加鎖,隨便存取,只有在更新的時候,才會從原來的資料複製一個副本出來,然後修改這個副本,最後把原資料替換成當前的副本。修改操作的同時,讀操作不會被阻塞,而是繼續讀取舊的資料。

    /** The lock protecting all mutators */
    final transient ReentrantLock lock = new ReentrantLock();

    /** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

原始碼裡用到了ReentrantLock鎖和volatile關鍵字,會在《資深程式設計師修煉》專欄中做全面深度講解。

LinkedList

LinkedListArrayList同屬於List集合。其共同特點可歸納為:

儲存單列資料的集合,儲存的資料是有序並且是可以重複的。

但兩者也有不同,往下看吧

底層實現

LinkedList類的底層實現的資料結構是一個雙向連結串列。同時還實現了Deque介面,所以會有些佇列的特性,會在下面講。

class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

先簡單說一下連結串列這種資料結構,與陣列相反,連結串列是一種物理儲存單元上非連續、非順序的儲存結構,一個最簡單的連結串列(單連結串列)有節點Node和數值value組成。通俗的講,就像串在一起的小魚乾,中間用線連著。

transient Node<E> first;

transient Node<E> last;

連結串列中儲存著對最後一個節點的參照,這就是雙端連結串列

在單連結串列的結點中增加一個指向其前驅的pre指標就是雙向連結串列,一種犧牲空間換時間的做法。

雙端連結串列不同於雙向連結串列,切記!

關於連結串列更詳細程式碼級講解會放《糊塗演演算法》專欄更新。敬請期待!

簡單瞭解過後分析一下連結串列的特點:

  • 查詢速度慢,因為是非連續空間,沒有下標。想像你需要在一份名單上找到你的名字,沒有序號,你只能從頭開始一個一個的看。
  • 刪改速度快,因為非連續,也就沒有那麼多約束。想像從一根項鍊上扣下來一塊,只需要改變參照就可以了,不會牽一髮而動全身。
  • 元素有序,可重複。

如何解決查詢慢的問題?

如果我查詢的元素在尾部,則需要遍歷整個連結串列,所以有了雙端連結串列。

即使不在尾部,我如果只能一個方向遍歷,也很麻煩,所以有了雙向佇列,犧牲空間換時間。

那麼空間可不可以再犧牲一點?

可以,就是跳躍連結串列,簡稱「跳錶」。

通過建立多級索引來加快查詢速度。

執行緒安全問題

老辦法,看看add()方法。分為「頭插法」和「尾插法」。

    /**
     * Inserts the specified element at the beginning of this list.
     *
     * @param e the element to add
     */
    public void addFirst(E e) {
        linkFirst(e);
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #add}.
     *
     * @param e the element to add
     */
    public void addLast(E e) {
        linkLast(e);
    }

都沒加鎖,百分之一百的不安全。

如何解決執行緒不安全問題

1.ConcurrentLinkedQueue

一個新的類,位於java.util.concurrent(juc)包下。實現了Queue介面。

class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
        implements Queue<E>, java.io.Serializable{}

使用violate關鍵字實現加鎖。

 private transient volatile Node<E> head;

 private transient volatile Node<E> tail;

1.Collections

ArrayList一樣,使用Collections.synchronizedList()

Map:儲存雙列資料的集合,通過鍵值對儲存資料,儲存 的資料是無序的,Key值不能重複,value值可以重複

和ArrayList對比一下

共同點:有序,可重複。執行緒不安全。

不同點:底層架構,查詢和刪改的速度

完整講解

集合完整講解

書單1

  • Java核心技術 卷1 基礎知識
  • Java核心技術 卷2 高階特性
  • 程式設計之美
  • Java程式設計思想
  • Java8實戰
  • Java語言導學
  • 瘋狂Java:突破程式設計師基本功的16課
  • 碼出高效:Java開發手冊
  • Java語言程式設計
  • Java工程師修煉之道
  • Java技術手冊(第6版)
  • Java深度歷險

JVM

重點來了,Java程式設計師一定要深入研究的內容

書單2

  • 揭祕Java虛擬機器器-JVM設計原理與實現
  • 垃圾回收演演算法與實現
  • 垃圾收集
  • 深入理解Java虛擬機器器
  • JVM實用引數系列
  • JVM思維導圖

完整講解

JVM完整講解

多執行緒

理解多執行緒,才能更好的理解框架原始碼,進行高並行的架構設計,重中之重。

並行和並行

並行:多個任務在同一個 CPU 核上,按細分的時間片輪流(交替)執行,從邏輯上來看那些任務是同時執行。

並行:多個處理器或多核處理器同時處理多個任務。

舉例:

並行 = 兩個佇列和一臺咖啡機。

並行 = 兩個佇列和兩臺咖啡機。

執行緒和程序

一個程式下至少有一個程序,一個程序下至少有一個執行緒,一個程序下也可以有多個執行緒來增加程式的執行速度。

守護執行緒

守護執行緒是執行在後臺的一種特殊程序。它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。在 Java 中垃圾回收執行緒就是特殊的守護執行緒。

建立執行緒4種方式

  • 繼承 Thread 重新 run 方法;

  • 實現 Runnable 介面;

  • 實現 Callable 介面。

  • 執行緒池

synchronized 底層實現

synchronized 是由一對 monitorenter/monitorexit 指令實現的,monitor 物件是同步的基本實現單元。

在 Java 6 之前,monitor 的實現完全是依靠作業系統內部的互斥鎖,因為需要進行使用者態到核心態的切換,所以同步操作是一個無差別的重量級操作,效能也很低。

但在 Java 6 的時候,Java 虛擬機器器 對此進行了大刀闊斧地改進,提供了三種不同的 monitor 實現,也就是常說的三種不同的鎖:偏向鎖(Biased Locking)、輕量級鎖和重量級鎖,大大改進了其效能。

synchronized 和 volatile 的區別

volatile 是變數修飾符;synchronized 是修飾類、方法、程式碼段。

volatile 僅能實現變數的修改可見性,不能保證原子性;而 synchronized 則可以保證變數的修改可見性和原子性。

volatile 不會造成執行緒的阻塞;synchronized 可能會造成執行緒的阻塞。

synchronized 和 Lock 區別

synchronized 可以給類、方法、程式碼塊加鎖;而 lock 只能給程式碼塊加鎖。

synchronized 不需要手動獲取鎖和釋放鎖,使用簡單,發生異常會自動釋放鎖,不會造成死鎖。

lock 需要自己加鎖和釋放鎖,如果使用不當沒有 unLock()去釋放鎖就會造成死鎖。

通過 Lock 可以知道有沒有成功獲取鎖,而 synchronized 卻無法辦到。

synchronized 和 ReentrantLock 區別

synchronized 早期的實現比較低效,對比 ReentrantLock,大多數場景效能都相差較大,但是在 Java 6 中對 synchronized 進行了非常多的改進。

主要區別如下:

ReentrantLock 使用起來比較靈活,但是必須有釋放鎖的配合動作;

ReentrantLock 必須手動獲取與釋放鎖,而 synchronized 不需要手動釋放和開啟鎖;

ReentrantLock 只適用於程式碼塊鎖,而 synchronized 可用於修飾方法、程式碼塊等。

volatile 標記的變數不會被編譯器優化;synchronized 標記的變數可以被編譯器優化。

書單3

  • 實戰Java高並行程式設計
  • 圖解Java多執行緒設計模式
  • JAVA並行程式設計實站
  • Java並行程式設計從入門到精通
  • Java並行程式設計的藝術
  • Java並行程式設計核心方法與框架
  • Java並行程式設計之美
  • Java 多執行緒程式設計核心技術
  • Java高並行程式設計詳解

設計模式

好多人覺得設計模式模式,那是因為你學的還不夠深入,還沒有看過原始碼,所以我特意將設計模式往前放了。

今天我們一塊看一下簡單工廠模式,其實他不屬於23種設計模式,但為了更好的理解後面的工廠方法抽象工廠,我們還是需要先了解一下。

image-20211004190949835

定義

官方定義

定義一個工廠類,他可以根據引數的不同返回不同類的範例,被建立的範例通常都具有共同的父類別。

通俗解讀

我們不必關心物件的建立細節,只需要根據不同引數獲取不同產品即可。

難點:寫好我們的工廠。

結構圖

程式碼演示

本文原始碼:簡單工廠模式原始碼 提取碼: qr5h

目錄結構

建議跟著一條學設計模式的小夥伴都建一個maven工程,並安裝lombok依賴和外掛。

並建立如下包目錄,便於歸納整理。

pom如下

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>

開發場景

汽車製造工廠,既可以生產跑車,也可以生產SUV,未來還會生產新能源汽車。

程式碼實現

1.建立抽象產品Car

public abstract class Car {
    public String color;
    abstract void run();
}

2.建立具體產品

SuvCar

public class SuvCar extends Car{
    public SuvCar(){
        this.color="green";
    }

    @Override
    public void run() {
        System.out.println("SuvCar running---------");
    }
}

SportsCar

public class SportsCar extends Car{

    public SportsCar(){
        this.color="red";
    }

    @Override
    public void run() {
        System.out.println("SportsCar running-------");
    }
}

3.建立靜態工廠

在簡單工廠模式中用於被建立範例的方法通常為靜態方法,因此簡單工廠模式又被成為靜態工廠方法(Static Factory Method)

/**
 * 簡單/靜態工廠,少數產品
 */
public class CarFactory {

   public static Car getCar(String type){
        if (type.equals("sport")){
            return new SportsCar();
        }else if (type.equals("suv")){
            return new SuvCar();
        }else {
            return null;
        }
    }
}

4.編寫測試類

public class MainTest {
    public static void main(String[] args) {
        SportsCar sport = (SportsCar) CarFactory.getCar("sport");
        sport.run();
        System.out.println(sport.color);
    }
}

5.輸出結果

介面和抽象類

補充一個知識

介面和抽象類有什麼區別?

什麼時候用介面,什麼時候用抽象類?

介面和抽象類有什麼區別?

  • 介面是針對方法的整合,抽象類是針對子類的整合。
  • 人有男人,女人,人是抽象類。人可以吃東西,狗也可以吃東西,吃東西這個動作是介面。
  • 介面可以多繼承,抽象類不行。
  • 介面中基本資料型別為static, 而抽類象不是。
  • 抽象類有構造器,方法可以實現,除了不能被範例化,和普通類沒有區別,介面不是。

什麼時候用介面,什麼時候用抽象類?

  • 當你關注一個事物的本質的時候,用抽象類;當你關注一個操作的時候,用介面。
  • 再簡單點說,有屬性定義的時候,用抽象類,只有方法的時候,用介面。

應用場景

  • 工廠類負責建立對的物件比較少,因為不會造成工廠方法中的業務邏輯過於複雜

  • 使用者端只知道傳入工廠類的引數,對如何建立物件不關心

  • 由於簡單工廠很容易違反高內聚責任分配原則,因此一般只在很簡單的情況下應用。

總結

優點

  • 通過工廠類,無需關注生產的細節,只需要傳遞對應引數即可。
  • 可以引入組態檔,在不修改使用者端程式碼的情況下更換和新增新的具體產品類。

缺點

  • 違背開閉原則,擴充套件不易。
  • 工廠類職責過重,一旦異常,系統癱瘓。
  • 無法動態的增加產品,擴充套件困難。

問題:在不修改的工廠的前提下,怎麼生產新能源汽車?下一節的工廠方法模式給大家講解。

更多設計模式

更多設計模式

書單4

SSM框架

這對於初學者來說,是一個坎,前幾年學完這些,已經可以開始找工作了,所以恭喜你能堅持帶這裡,勝利就在前方。

書單5

  • Spring 技術內幕:深入解析Spring架構與設計原理(第2版)
  • Spring 實戰
  • Spring揭祕
  • Spring Boot實戰
  • Spring5 高階程式設計
  • Spring Framework 5.x參考檔案
  • Spring從入門到精通
  • 深入淺出Spring Boot2
  • JavaEE開發的顛覆者 Spring Boot實戰、
  • 一本小小的Mybatis書
  • mybatis入門到精通
  • 看透SpringMVC原始碼分許

Redis

隨著QPS的逐漸升高,傳統的mysql資料庫已經無法滿足。所以有了基於記憶體的redis快取資料庫來儲存熱點資料。

書單6

特別推薦:redis深度歷險

Zookeeper

Zookeeper作為統一組態檔管理和叢集管理框架,是後續學習其他框架的基礎,在微服務中,還可以用來做註冊中心。

書單7

一定要看的兩本書。

Kafka

書單8

其他書單

架構設計

image-20211017134205378

MySql

資料結構與演演算法

  • 演演算法圖解
  • 圖解資料結構
  • 大話資料結構
  • 演演算法導論(第三版)
  • 演演算法的樂趣
  • 資料結構與抽象 Java語言描述 第4版
  • 資料結構與演演算法經典問題解析
  • 演演算法問題整理
  • 排序與查詢
  • Java資料結構和演演算法

image-20211017134351353

學習心得

1.按計劃行事

凡事預則立,不預則廢。一個好的計劃是成功的一半,而這一半,一條已經幫你整理好了,你只需要收藏即可。

該路線圖左側為主路線,需循序漸進,步步為營;右側為輔助路線,需貫穿始終,熟練掌握。

建議做好時間規劃,不斷的提高自己的學習效率,學習過程中儘量把手機調至靜音給自己一個安靜的學習環境和氛圍。

2.抱團生長

獨腳難行,孤掌難鳴,一個人的力量終究是有限的,一個人的旅途也註定是孤獨的。當你定好計劃,懷著滿腔熱血準備出發的時候,一定要找個夥伴,和唐僧西天取經一樣,師徒四人團結一心才能通過九九八十一難。

在學習過程中看下自己身邊有沒有Java這方面的大神,儘量多問,多交流,如果沒有的話,來找我,我一定知無不言言無不盡,還可以給你找一群志同道合的人。水漲船高,柴多火旺,就是這個道理,閉門造車註定會半途而廢。

3.貴在堅持

駑馬十駕,功在不捨。自學Java非一日之功,你知道的越多,不知道的也越多。所以,為自己找一個動力,為了改變命運,或是為了心愛的人,或是為了讓別人高看一眼。男兒何不帶吳鉤,收取關山十五州。歲月無情,餘生有涯,請將生活扛在肩上,只顧風雨兼程。


⭐️學習路線、電子書⭐️👇點選下方卡片 關注後回覆「1024」獲取👇