国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

五萬字15張導(dǎo)圖Java自學路線,小白零基礎(chǔ)入門,程序員進階,收藏這篇就夠了

suosuopuo / 4249人閱讀

摘要:本文收錄于技術(shù)專家修煉文中配套資料合集路線導(dǎo)圖高清源文件點擊跳轉(zhuǎn)到文末點擊底部卡片回復(fù)資料領(lǐng)取哈嘍,大家好,我是一條最近粉絲問我有沒有自學路線,有了方向才能按圖索驥,事半功倍。

本文收錄于《技術(shù)專家修煉》

文中配套資料合集
路線導(dǎo)圖高清源文件

點擊跳轉(zhuǎn)到文末點擊底部卡片回復(fù)「資料」領(lǐng)取

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

最近粉絲問我有沒有Java自學路線,有了方向才能按圖索驥,事半功倍。

我一想確實如此,自己去年總結(jié)了一份,但有些地方需要修改,索性利用國慶假期,重新整理一份。

沒錯,就是這篇文章,本文分為學習路線配套資料兩部分。

文章目錄

自學路線

0.路線導(dǎo)學

Java學習,如逆水行舟,不進則退。而自學,逆水還得加個水逆,難上加難。

所以我們要做好打持久戰(zhàn)的準備。

按計劃行事

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

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

建議做好時間規(guī)劃,不斷的提高自己的學習效率,學習過程中盡量把手機調(diào)至靜音給自己一個安靜的學習環(huán)境和氛圍。

抱團生長

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

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

貴在堅持

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

1.Java基礎(chǔ)

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

基本數(shù)據(jù)類型

Java 語言提供了 8 種基本類型,大致分為 4 類(8位=1字節(jié))

  • 整數(shù)型
    • byte - 1字節(jié)
    • short - 2字節(jié)
    • int - 4字節(jié)
    • long - 8字節(jié),賦值時一般在數(shù)字后加上 lL
  • 浮點型
    • float - 4字節(jié),直接賦值時必須在數(shù)字后加上 fF
    • double - 8字節(jié),賦值時一般在數(shù)字后加 dD
  • 字符型
    • char - 2字節(jié),存儲 Unicode 碼,用單引號賦值
  • 布爾型
    • boolean - 1字節(jié),只有 true 和 false 兩個取值,一個字節(jié)就夠了

引用數(shù)據(jù)類型

簡單來說,所有的非基本數(shù)據(jù)類型都是引用數(shù)據(jù)類型,除了基本數(shù)據(jù)類型對應(yīng)的引用類型外,類、 接口類型、 數(shù)組類型、 枚舉類型、 注解類型、 字符串型都屬于引用類型。

主要有以下區(qū)別:

1、存儲位置

  • 基本變量類型在方法中定義的非全局基本數(shù)據(jù)類型變量的具體內(nèi)容是存儲在棧中的
  • 引用數(shù)據(jù)類型變量其具體內(nèi)容都是存放在堆中的,而棧中存放的是其具體內(nèi)容所在內(nèi)存的地址

2、傳遞方式

  • 基本數(shù)據(jù)類型是按值傳遞
  • 引用數(shù)據(jù)類型是按引用傳遞

訪問修飾符

訪問修飾符就是限制變量的訪問權(quán)限的。

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

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

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

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

后來你老了,明白了開源才是共贏,就設(shè)置成了public(公有的);

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

static關(guān)鍵字

主要意義:

我日常調(diào)用方法都是對象.方法,static的主要意義就是可以創(chuàng)建獨立于具體對象的域變量或者方法。也就是實現(xiàn)即使沒有創(chuàng)建對象,也能使用屬性和調(diào)用方法!

另一個比較關(guān)鍵的作用就是 用來形成靜態(tài)代碼塊以優(yōu)化程序性能static塊可以置于類中的任何地方,可以有多個。在類初次被加載的時候,會按照static塊的順序來執(zhí)行每個static塊,并且只會執(zhí)行一次,可以用來優(yōu)化程序性能

通俗理解:

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

final關(guān)鍵字

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

將類、方法、變量聲明為final能夠提高性能,這樣JVM就有機會進行估計,然后優(yōu)化。

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

  • final關(guān)鍵字可以用于成員變量、本地變量、方法以及類。
  • final成員變量必須在聲明的時候初始化或者在構(gòu)造器中初始化,否則就會報編譯錯誤。
  • 不能夠?qū)inal變量再次賦值。
  • final方法不能被重寫。
  • final類不能被繼承。
  • 接口中聲明的所有變量本身是final的。
  • final和abstract這兩個關(guān)鍵字是反相關(guān)的,final類就不可能是abstract的。

面向?qū)ο笕筇匦?/h3>

封裝

1.什么是封裝

封裝又叫隱藏實現(xiàn)。就是只公開代碼單元的對外接口,而隱藏其具體實現(xiàn)。

其實生活中處處都是封裝,手機,電腦,電視這些都是封裝。你只需要知道如何去操作他們,并不需要知道他們里面是怎么構(gòu)造的,怎么實現(xiàn)這個功能的。

2.如何實現(xiàn)封裝

在程序設(shè)計里,封裝往往是通過訪問控制實現(xiàn)的。也就是剛才提到的訪問修飾符。

3.封裝的意義

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

好比只要你手機的充電接口不變,無論以后手機怎么更新,你依然可以用同樣的數(shù)據(jù)線充電或者與其他設(shè)備連接。

封裝的設(shè)計使使整個軟件開發(fā)復(fù)雜度大大降低。我只需要使用別人的類,而不必關(guān)心其內(nèi)部邏輯是如何實現(xiàn)的。我能很容易學會使用別人寫好的代碼,這就讓軟件協(xié)同開發(fā)的難度大大降低。

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

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

繼承

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

多態(tài)

多態(tài)的定義:

指允許不同類的對象對同一消息做出響應(yīng)。即同一消息可以根據(jù)發(fā)送對象的不同而采用多種不同的行為方式。(發(fā)送消息就是函數(shù)調(diào)用)

簡單來說,同樣調(diào)用攻擊這個方法,后裔的普攻和亞瑟的普攻是不一樣的。

多態(tài)的條件:

  • 要有繼承
  • 要有重寫
  • 父類引用指向子類對象

多態(tài)的好處:

多態(tài)對已存在代碼具有可替換性。

多態(tài)對代碼具有可擴充性。

它在應(yīng)用中體現(xiàn)了靈活多樣的操作,提高了使用效率。

多態(tài)簡化對應(yīng)用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤為突出和重要。

Java中多態(tài)的實現(xiàn)方式:

  • 接口實現(xiàn)
  • 繼承父類進行方法重寫
  • 同一個類中進行方法重載

完整講解

Java基礎(chǔ)完整講解

入門練習案例

《入門練習100例》

2.JavaWeb

JavaWeb是用Java技術(shù)來解決相關(guān)web互聯(lián)網(wǎng)領(lǐng)域的技術(shù)棧。Web就是網(wǎng)頁,分為靜態(tài)和動態(tài)。涉及 的知識點主要包括jsp,servlet,tomcat,http,MVC等知識。

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

HTTP網(wǎng)絡(luò)請求方式

  • GET:最常用的方式,用來向服務(wù)器請求數(shù)據(jù),沒有請求體,請求參數(shù)放在URL后面。
  • POST:用于向表單提交數(shù)據(jù),傳送的數(shù)據(jù)放在請求體中。
  • PUT:用來向服務(wù)器上傳文件,一般對應(yīng)修改操作,POST用于向服務(wù)器發(fā)送數(shù)據(jù),PUT用于向服務(wù)器儲存數(shù)據(jù)。沒有驗證機制,任何人都可以操作,存在安全問題。具有冪等性。
  • DELETE:用于刪除服務(wù)器上的文件,具有冪等性。同樣存在安全問題。
  • HEAD:用HEAD進行請求服務(wù)器時,服務(wù)器只返回響應(yīng)頭,不返回響應(yīng)體。與GET一樣沒有請求體,常用于檢查請求的URL是否有效。
  • PATCH:對資源進行部分修改。與PUT區(qū)別在于,PUT是修改所有資源,替代它,而PATCH只是修改部分資源。
  • TRACE:用來查看一個請求,經(jīng)過網(wǎng)關(guān),代理到達服務(wù)器,最后請求的變換。因安全問題被禁用。
  • OPTIONS:當客戶端不清楚對資源操作的方法,可以使用這個,具有冪等性。

GET和POST

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

冪等性

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

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

如何保證冪等性

假設(shè)這樣一個場景:有時我們在填寫某些form表單時,保存按鈕不小心快速點了兩次,表中竟然產(chǎn)生了兩條重復(fù)的數(shù)據(jù),只是id不一樣。

這是一個比較常見的冪等性問題,在高并發(fā)場景下會變得更加復(fù)雜,那怎么保證接口的冪等性呢?

1.insert前select

插入數(shù)據(jù)前先根據(jù)某一字段查詢一下數(shù)據(jù)庫,如果已經(jīng)存在就修改,不存在再插入。

2.加鎖

加鎖可解決一切問題,但也要考慮并發(fā)性。

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

悲觀鎖的并發(fā)性較低,更適合使用在防止數(shù)據(jù)重復(fù)的場景,注意冪等性不光是防止重復(fù)還需要結(jié)果相同。

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

分布式鎖應(yīng)用在高并發(fā)場景,主要用redis來實現(xiàn)。

3.唯一索引

通過數(shù)據(jù)庫的唯一索引來保證結(jié)果的一致性和數(shù)據(jù)的不重復(fù)。

4.Token

兩次請求,第一請求拿到token,第二次帶著token去完成業(yè)務(wù)請求。

常見的網(wǎng)絡(luò)狀態(tài)碼

網(wǎng)絡(luò)狀態(tài)碼共三位數(shù)字組成,根據(jù)第一個數(shù)字可分為以下幾個系列:

1xx(信息性狀態(tài)碼)

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

包括:100、101、102

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

2xx(成功狀態(tài)碼)

表示成功處理了請求的狀態(tài)代碼。

200:請求成功,表明服務(wù)器成功了處理請求。

202:服務(wù)器已接受請求,但尚未處理。

204:服務(wù)器成功處理了請求,但沒有返回任何內(nèi)容。

206:服務(wù)器成功處理了部分 GET 請求。

3xx(重定向狀態(tài)碼)

300:針對請求,服務(wù)器可執(zhí)行多種操作。

301:永久重定向

302:臨時性重定向

303:303與302狀態(tài)碼有著相同的功能,但303狀態(tài)碼明確表示客戶端應(yīng)當采用GET方法獲取資源。

301和302的區(qū)別?

301比較常用的場景是使用域名跳轉(zhuǎn)。比如,我們訪問 http://www.baidu.com 會跳轉(zhuǎn)到https://www.baidu.com,發(fā)送請求之后,就會返回301狀態(tài)碼,然后返回一個location,提示新的地址,瀏覽器就會拿著這個新的地址去訪問。

302用來做臨時跳轉(zhuǎn)比如未登陸的用戶訪問用戶中心重定向到登錄頁面。

4xx(客戶端錯誤狀態(tài)碼)

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

401:表示發(fā)送的請求需要有通過HTTP認證的認證信息。比如token失效就會出現(xiàn)這個問題。

403:被拒絕,表明對請求資源的訪問被服務(wù)器拒絕了。

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

5xx(服務(wù)器錯誤狀態(tài)碼)

500:服務(wù)器本身發(fā)生錯誤,可能是Web應(yīng)用存在的bug或某些臨時的故障。

502:該狀態(tài)碼表明服務(wù)器暫時處于超負載或正在進行停機維護,現(xiàn)在無法處理請求。

??有時候返回的狀態(tài)碼響應(yīng)是錯誤的,比如Web應(yīng)用程序內(nèi)部發(fā)生錯誤,狀態(tài)碼依然返回200

轉(zhuǎn)發(fā)和重定向

上面提到了重定向,那你知道什么是轉(zhuǎn)發(fā)嗎?

1.轉(zhuǎn)發(fā)

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

客戶瀏覽器發(fā)送http請求,web服務(wù)器接受此請求,調(diào)用內(nèi)部的一個方法在容器內(nèi)部完成請求處理和轉(zhuǎn)發(fā)動作,將目標資源發(fā)送給客戶。

整個轉(zhuǎn)發(fā)一個請求,一個響應(yīng),地址欄不會發(fā)生變化,不能跨域訪問。

2.重定向

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

客戶瀏覽器發(fā)送http請求,web服務(wù)器接受后發(fā)送302狀態(tài)碼響應(yīng)及對應(yīng)新的location給客戶瀏覽器,客戶瀏覽器發(fā)現(xiàn)是302響應(yīng),則自動再發(fā)送一個新的http請求,請求url是新的location地址,服務(wù)器根據(jù)此請求尋找資源并發(fā)送給客戶。

兩個請求,兩個響應(yīng),可以跨域。

Servlet

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

servlet其實就是一個java程序,他主要是用來解決動態(tài)頁面的問題。

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

servlet存在于tomcat之中,用來網(wǎng)絡(luò)請求與響應(yīng),但他的重心更在于業(yè)務(wù)處理,我們訪問京東和淘寶的返回的商品是不一樣的,就需要程序員去編寫,目前MVC三層架構(gòu),我們都是在service層處理業(yè)務(wù),但這其實是從servlet中抽取出來的。

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

Servlet的生命周期

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

  • 初始化階段 調(diào)用init()方法
  • 響應(yīng)客戶請求階段  調(diào)用service()方法-àdoGet/doPost()
  • 終止階段  調(diào)用destroy()方法

session、cookie、token

首先我們要明白HTTP是一種無狀態(tài)協(xié)議,怎么理解呢?很簡單

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

這段對話都熟悉吧,HTTP就是那個大爺,那如果我們就直接把“大爺”放給用戶,用戶不用干別的了,就不停的登錄就行了。

既然“大爺不靠譜”,我們找“大娘”去吧。

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

為了解決用戶頻繁登錄的問題,在服務(wù)端和客戶端共同維護一個狀態(tài)——會話,就是所謂session,我們根據(jù)會話id判斷是否是同一用戶,這樣用戶就開心了。

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

但是問題依然存在,如果兄弟掛了怎么辦,兄弟們之間的數(shù)據(jù)怎么同步,用戶1把session存放在機器A上,下次訪問時負載均衡到了機器B,完了,找不到,用戶又要罵娘。

這時有人思考,為什么一定要服務(wù)端保存呢,讓客戶端自己保存不就好了,所以就誕生了cookie,下一次請求時客戶段把cookie發(fā)送給服務(wù)器,說我已經(jīng)登錄了。

但是空口無憑,服務(wù)器怎么知道哪個cookie是我發(fā)過去的呢?如何驗證成了新的問題。

有人想到了一個辦法,用加密令牌,也就是token,服務(wù)器發(fā)給客戶端一個令牌,令牌保存加密后id和密鑰,下一次請求時通過headers傳給服務(wù)端,由于密鑰別人不知道,只有服務(wù)端知道,就實現(xiàn)了驗證,且別人無法偽造。

MVC與三層架構(gòu)

三層架構(gòu)與MVC的目標一致:都是為了解耦和、提高代碼復(fù)用。MVC是一種設(shè)計模式,而三層架構(gòu)是一種軟件架構(gòu)。

MVC

Model 模型

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

View 視圖

用戶看到的頁面和與用戶的交互。包含各種表單。 實現(xiàn)視圖用到的技術(shù)有html/css/jsp/js等前端技術(shù)。

常用的web 容器和開發(fā)工具

Controller 控制器

控制器負責將視圖與模型一一對應(yīng)起來。相當于一個模型分發(fā)器。接收請求,并將該請求跳轉(zhuǎn)(轉(zhuǎn)發(fā),重定向)到模型進行處理。模型處理完畢后,再通過控制器,返回給視圖中的請求處。

三層架構(gòu)

表現(xiàn)層(UI)(web層)、業(yè)務(wù)邏輯層(BLL)(service層)、數(shù)據(jù)訪問層(DAL)(dao層) ,再加上實體類庫(Model)

  • 實體類庫(Model),在Java中,往往將其稱為Entity實體類。數(shù)據(jù)庫中用于存放數(shù)據(jù),而我們通常選擇會用一個專門的類來抽象出數(shù)據(jù)表的結(jié)構(gòu),類的屬性就一對一的對應(yīng)這表的屬性。一般來說,Model實體類庫層需要被DAL層,BIL層和UI層引用。
  • 數(shù)據(jù)訪問層(DAL),主要是存放對數(shù)據(jù)類的訪問,即對數(shù)據(jù)庫的添加、刪除、修改、更新等基本操作,DAL就是根據(jù)業(yè)務(wù)需求,構(gòu)造SQL語句,構(gòu)造參數(shù),調(diào)用幫助類,獲取結(jié)果,DAL層被BIL層調(diào)用
  • 業(yè)務(wù)邏輯層(BLL),BLL層好比是橋梁,將UI表示層與DAL數(shù)據(jù)訪問層之間聯(lián)系起來。所要負責的,就是處理涉及業(yè)務(wù)邏輯相關(guān)的問題,比如在調(diào)用訪問數(shù)據(jù)庫之前,先處理數(shù)據(jù)、判斷數(shù)據(jù)。

完整講解

JavaWeb完整講解

3.集合

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

ArrayList

底層實現(xiàn)

由什么組成,我說了不算,看源碼。怎么看呢?

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.     * 翻譯     * 數(shù)組緩沖區(qū),ArrayList的元素被存儲在其中。ArrayList的容量是這個數(shù)組緩沖區(qū)的長度。     * 任何空的ArrayList,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,     * 當?shù)谝粋€元素被添加時,將被擴展到DEFAULT_CAPACITY。     */    transient Object[] elementData; 

毋庸置疑,底層由數(shù)組組成,那數(shù)組的特點就是ArrayList的特點。

  • 由于數(shù)組以一塊連續(xù)的內(nèi)存空間,每一個元素都有對應(yīng)的下標,查詢時間復(fù)雜度為O(1)。好比你去住酒店,每個房間都挨著,房門都寫著房間號。你想找哪一間房是不是很容易。
  • 相對的,一塊連續(xù)的內(nèi)存空間你想打破他就沒那么容易,牽一發(fā)而動全身,所以新增和刪除的時間復(fù)雜度為O(n),想像你在做excel表格的時候,想增加一列,后面的列是不是都要跟著移動。
  • 元素有序,可重復(fù)。可用在大多數(shù)的場景,這個就不需要過多解釋了。

擴容

我們知道數(shù)組是容量不可變的數(shù)據(jù)結(jié)構(gòu),隨著元素不斷增加,必然要擴容。

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

1.初始化容量為10,也可以指定容量創(chuàng)建。

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

2.數(shù)組進行擴容時,是將舊數(shù)據(jù)拷貝到新的數(shù)組中,新數(shù)組容量是原容量的1.5倍。(這里用位運算是為了提高運算速度)

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

3.擴容代價是很高得,因此再實際使用時,我們因該避免數(shù)組容量得擴張。盡可能避免數(shù)據(jù)容量得擴張。盡可能,就至指定容量,避免數(shù)組擴容的發(fā)生。

為什么擴容是1.5倍?

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

所以,1.5是均衡了空間占用和擴容次數(shù)考慮的。

線程安全問題

怎么看線程安全?說實話我以前都不知道,看網(wǎng)上說安全就安全,說不安全就不安全。

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

    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++;    }

沒有加鎖,所以線程不安全

在多線程的情況下,插入數(shù)據(jù)的時可能會造成數(shù)據(jù)丟失,一個線程在遍歷,另一個線程修改,會報ConcurrentModificationException(并發(fā)修改異常)錯誤.

多線程下使用怎么保證線程安全?

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

早就給你準備了線程安全的類。

1.Vector

Vector是一個線程安全的List類,通過對所有操作都加上synchronized關(guān)鍵字實現(xiàn)。

找到add方法,可以看到被synchronized關(guān)鍵字修飾,也就是加鎖,但synchronized是重度鎖,并發(fā)性太低,所以實際一般不使用,隨著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也有對應(yīng)的方法

3.CopyOnWrite(寫時復(fù)制)

寫時復(fù)制,簡稱COW,是計算機程序設(shè)計領(lǐng)域中的一種通用優(yōu)化策略。

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

當某個調(diào)用者修改資源內(nèi)容時,系統(tǒng)會真正復(fù)制一份副本給該調(diào)用者,而其他調(diào)用者所見到的最初的資源仍然保持不變。修改完成后,再把新的數(shù)據(jù)寫回去。

通俗易懂的講,假設(shè)現(xiàn)在有一份班級名單,但有幾個同學還沒有填好,這時老師把文件通過微信發(fā)送過去讓同學們填寫(復(fù)制一份),但不需要修改的同學此時查看的還是舊的名單,直到有同學修改好發(fā)給老師,老師用新的名單替換舊的名單,全班同學才能查看新的名單。

共享讀,分開寫。讀寫分離,寫時復(fù)制。

在java中,通過CopyOnWriteArrayListCopyOnWriteArraySet容器實現(xiàn)了 COW 思想。

平時查詢的時候,都不需要加鎖,隨便訪問,只有在更新的時候,才會從原來的數(shù)據(jù)復(fù)制一個副本出來,然后修改這個副本,最后把原數(shù)據(jù)替換成當前的副本。修改操作的同時,讀操作不會被阻塞,而是繼續(xù)讀取舊的數(shù)據(jù)。

    /** 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關(guān)鍵字,會在《資深程序員修煉》專欄中做全面深度講解。

LinkedList

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

存儲單列數(shù)據(jù)的集合,存儲的數(shù)據(jù)是有序并且是可以重復(fù)的。

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

底層實現(xiàn)

LinkedList類的底層實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)是一個雙向鏈表。同時還實現(xiàn)了Deque接口,所以會有些隊列的特性,會在下面講。

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

先簡單說一下鏈表這種數(shù)據(jù)結(jié)構(gòu),與數(shù)組相反,鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),一個最簡單的鏈表(單鏈表)有節(jié)點Node和數(shù)值value組成。通俗的講,就像串在一起的小魚干,中間用線連著。

transient Node<E> first;transient Node<E> last;

鏈表中保存著對最后一個節(jié)點的引用,這就是雙端鏈表

在單鏈表的結(jié)點中增加一個指向其前驅(qū)的pre指針就是雙向鏈表,一種犧牲空間換時間的做法。

雙端鏈表不同于雙向鏈表,切記!

關(guān)于鏈表更詳細代碼級講解會放《糊涂算法》專欄更新。敬請期待!

簡單了解過后分析一下鏈表的特點:

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

如何解決查詢慢的問題?

如果我查找的元素在尾部,則需要遍歷整個鏈表,所以有了雙端鏈表。

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

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

可以,就是跳躍鏈表,簡稱「跳表」。

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

線程安全問題

老辦法,看看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.     *     * 

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)包下。實現(xiàn)了Queue接口。

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

使用violate關(guān)鍵字實現(xiàn)加鎖。

 private transient volatile Node<E> head; private transient volatile Node<E> tail;

1.Collections

ArrayList一樣,使用Collections.synchronizedList()

Map:存儲雙列數(shù)據(jù)的集合,通過鍵值對存儲數(shù)據(jù),存儲 的數(shù)據(jù)是無序的,Key值不能重復(fù),value值可以重復(fù)

和ArrayList對比一下

共同點:有序,可重復(fù)。線程不安全。

不同點:底層架構(gòu),查詢和刪改的速度

完整講解

集合完整講解

4.JVM

重點來了,Java程序員一定要深入研究的內(nèi)容

JVM的體系架構(gòu)

JVM體系結(jié)構(gòu)如下圖所示,將按照從上到下的順序講解

類裝載器classloader

負責將class文件的字節(jié)碼內(nèi)容加載到內(nèi)存中并將這些內(nèi)容轉(zhuǎn)換成方法區(qū)中的運行時數(shù)據(jù)結(jié)構(gòu),class文件在文件開頭有特定標識(cafe babe:Java圖標——咖啡和橡樹)。

通俗來講:classloader相當于快遞員的作用,只負責加載,至于是否能運行,由Execution Engine決定

雙親委派機制

當一個類收到類加載請求,他會先把這個請求交給他的父類,只有父類無法完成這個請求時,子加載器才會嘗試自己去加載。

雙親委派的好處是保護Java核心類,比如加載位于rt.jar中的java.lang.Object,不管是哪個加載器加載的,最終都會交給啟動類加載器,這樣就保證了不同的類加載器得到的都是同一個Object對象。

代碼舉例:查看類是被那個加載器加載的

/** * @Author: 一條IT * @Date: 2020/12/3 21:28 */public class Test {    public static void main(String[] args) {        System.out.println(Object.class.getClassLoader());        System.out.println(Test.class.getClassLoader().getParent().getParent());        System.out.println(Test.class.getClassLoader().getParent());        System.out.println(Test.class.getClassLoader());    }}

輸出

nullnullsun.misc.Launcher$ExtClassLoader@1b6d3586sun.misc.Launcher$AppClassLoader@14dad5dc

因為Object是jdk自帶的,所以在加載的時候是走Bootstrap啟動類加載器,而Bootstrap加載器是C++語言寫的,所以在查的時候是null,報了NullPointException();Test類自己寫的,走AppClassLoder,他的父類是擴展加載器,再父類是啟動類加載器,也輸出Null

沙箱安全機制

主要是防止惡意代碼污染java源代碼,比如定義了一個類名為String所在包為java.lang,因為這個類本來是屬于jdk的,如果沒有沙箱安全機制的話,這個類將會污染到我所有的String,但是由于沙箱安全機制,所以就委托頂層的bootstrap加載器查找這個類,如果沒有的話就委托extsion,extsion沒有就到appclassloader,但是由于String就是jdk的源代碼,所以在bootstrap那里就加載到了,先找到先使用,所以就使用bootstrap里面的String,后面的一概不能使用,這就保證了不被惡意代碼污染。

垃圾回收

垃圾回收是重點難,先理解了垃圾回收,才能理解調(diào)優(yōu)的思路。

判斷垃圾

判斷是否是垃圾共有兩種方法。引用計數(shù)法和可達性分析

1.引用計數(shù)法

非常好理解,引用一次標記一次,沒有被標記的就是垃圾。

在堆中存儲對象時,在對象頭處維護一個counter計數(shù)器,如果一個對象增加了一個引用與之相連,則將counter++

如果一個引用關(guān)系失效則counter--。如果一個對象的counter變?yōu)?,則說明該對象已經(jīng)被廢棄,不處于存活狀態(tài),此時可以被回收。

2.引用計數(shù)的缺點

  • 效率低
  • 無法分析循環(huán)引用問題

3.可達性分析

類似的樹結(jié)構(gòu),從根結(jié)點出發(fā),即GC root,把有關(guān)系的對象用一顆樹鏈接起來

那么我們遍歷這棵樹,沒遍歷到的對象,就是垃圾

4.有哪些可以做GC Roots的對象?

  • 虛擬機棧(棧楨中的本地變量表)中的引用的對象
  • 方法區(qū)中的類靜態(tài)屬性引用的對象
  • 方法區(qū)中的常量引用的對象
  • 本地方法棧中JNI(Native方法)的引用的對象

回收算法

回收算法是垃圾回收的思想,回收器是垃圾回收的實現(xiàn)

1.標記-清除

兩次遍歷:

  • 標記垃

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/122555.html

相關(guān)文章

  • yolov5無從下手?一篇就夠,2021年全部基于最新配置的yolo入門升級路線

    摘要:的安裝下載好之后雙擊打開可執(zhí)行安裝文件選擇安裝目錄,需要的內(nèi)存較多,建議將其安裝在盤或者盤,不建議放在系統(tǒng)盤盤。 yolov5無從下手?一篇就夠的保姆級教程,202...

    AlanKeene 評論0 收藏0
  • Java學習路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強)

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學習一起進步歡迎點贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨立帶隊的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評論0 收藏0
  • Java3y文章目錄導(dǎo)航

    摘要:前言由于寫的文章已經(jīng)是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時間才會更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號:Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡單 注解就這么簡單 Druid數(shù)據(jù)庫連接池...

    KevinYan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<