1、第一階段邪修實戰總覽(9.1-9.30)
把第一階段(基礎夯實期)的學習計劃拆解成極具操作性的每日行動方案。這個計劃充分利用我“在職學習”的特殊優勢,強調“用輸出倒逼輸入”,確保每一分鐘的學習都直接服務于面試和實戰。
- 核心目標:構建起Java后端開發的知識樹主干,并能通過一個小型項目串聯起所有知識點。
- 核心策略:每天3小時雷打不動的高效學習(工作日可分散,周末集中攻堅)。
2、周目標(9.1-9.14)
Java核心+Sprig Boot破冰,能獨立使用Spring搭建Web后端并提供RESTful接口。
3、分日目標與邪修技巧
3.1、Day 9.1-9.2: Java基礎(變量、循環、條件分支、字符串操作)
- 行動:安裝JDK、IDE(IntelliJ IDEA),配置好環境。在菜鳥教程中學Java的變量、循環、條件分支、字符串操作這幾個板塊的內容,并用IDEA寫一個簡單的控制臺程序,我這里做了一個類似的程序叫"Data_Board",這是一個用Java編寫的廣告數據展示程序,采用面向對象設計思想重構,能夠從Excel文件讀取廣告數據,展示廣告花費、線索數量等關鍵指標,并提供多日期數據對比分析功能。程序支持數據自動計算(單個線索成本、私信轉化成本)和趨勢分析,具備良好的可擴展性和維護性。
- 邪修技巧:可以用TREA寫項目的README,定時更新一下,這樣后期我們面試之前可以仔細看看自己項目的編寫流程。
- 學習分享:這一階段的下載安裝就先不跟大家分享了,沒有那么多時間寫哈哈哈,如果大家有疑問想了解可以私聊我哈~這幾天的程序我會綜合在day5-day6中分享出來。
3.2、Day 9.3-9.4: Java面向對象(類、對象、繼承、多態、接口)
- 行動:在菜鳥教程中學Java的類、對象、繼承、多態、接口這幾個板塊的內容,將前兩天的"Data_Board"改造成面向對象風格。定義AdCampaign類,包含名稱、花費、收入等屬性,并封裝計算方法。
- 邪修技巧:思考為公司寫的那個程序,如果用OOP思想重構,該怎么設計?把這個思考過程寫在代碼注釋里,面試時可以聊。
3.3、Day 9.5-9.6: Java集合框架(List, Map, Set)和IO操作
- 行動:在菜鳥教程中學Java的List、Map、Set和IO操作這幾個板塊的內容,編寫程序從Excel文件(模擬數據源)讀取廣告數據,存入ArrayList或HashMap,并進行統計計算。
- 邪修技巧:這是面試重點。每學一個集合類,就去查一下它的底層實現(比如HashMap是數組+鏈表/紅黑樹),記下一兩句源碼分析,面試時拋出來是巨大加分項。
3.3.1、學習分享
- 根據前幾天所學,制作了一個采用面向對象設計思想重構,能夠從Excel文件讀取廣告數據,展示廣告花費、線索數量等關鍵指標,并提供多日期數據對比分析功能。程序支持數據自動計算(單個線索成本、私信轉化成本)和趨勢分析,具備良好的可擴展性和維護性。我把具體的代碼和README文檔放到了github里,點擊鏈接進入Data_Board-README文檔可以查看、下載并學習。
- 由于本人也是第一次正式使用Github來管理自己的代碼,以前總是自己存儲,所以現在也是仔細學了一下。給大家推薦幾個博客,大家如果想仔細學一下Github的話可以借鑒一下:
-
- Github入門教程,適合新手學習(非常詳細),這個博客的內容比較全面,有對GitHub和Git的介紹以及使用教程,唯一缺點是比較長,適合靜下心來仔細查看。
-
- 【2025版】最新GitHub新手用法詳解(適合新手入門)零基礎入門到精通,收藏這篇就夠了_github使用詳解,相較于上一篇博客,針對于Github和Git的講解少一點,但是基礎使用都是有的,趕進度可以試試。
-
- 如何解決:ssh: connect to host github.com port 22: Connection refused,這篇文檔解決了本地機器嘗試通過 SSH 協議連接 GitHub 的 22 端口時,連接被拒絕了的問題,如果你看不懂這個問題,你就切記當你碰到ssh: connect to host github.com port 22: Connection refused時,來找這個博客就行啦,別整什么防火墻、服務器之類的,就是個簡單的端口問題,跟著這個博客一步步解決即可。
3.3.2、集合類分析思考
ArrayList:
- 底層實現:基于
動態數組(transient Object[] elementData)
,默認初始容量10,支持自動擴容。 - 擴容機制:當添加元素導致不足時,通過grow()方法擴容,新容量為
oldCapacity + (oldCapacity >>1)
(即1.5倍),使用Array.copyof()
復制數組元素。 -
oldCapacity + (oldCapacity >>1)
是ArrayList擴容時計算“新容量”的核心公式,作用是把當前容量擴大到原來的1.5倍。
-
>>
是 Java 里的 “右移運算符”,簡單說就是 把一個數在二進制里往右挪幾位,效果相當于 “除以 2 的 n 次方”(n 是右移的位數)。這里用的是 oldCapacity >> 1(右移 1 位),效果就等于 oldCapacity ÷ 2(只取整數部分)。
- 關鍵代碼:
// 添加元素時的擴容判斷
ensureCapacityInternal(size + 1); // 確保容量足夠:檢查一下,現在的夠不夠再放 1 個新元素
elementData[size++] = e; // 直接在數組末尾賦值:添加新元素,并記錄現在的大小
// 代碼分析:
// 先確認有地方放新元素(不夠就擴容),然后把元素放到最后一個空位置,再更新已有的元素數量。
// ensureCapacityInternal(...):這是個 “檢查容量” 的工具方法,它會做兩件事:1、看看當前elementData的長度(也就是 “總抽屜數”)夠不夠裝size + 1個元素。2、如果夠(比如總抽屜數 10,要放第 10 個),就啥也不做,直接下一步;如果不夠(比如總抽屜數 10,要放第 11 個),就觸發 “擴容”(把抽屜數變成 15),然后再下一步。
// elementData[size] = e:往 “元素數組” 的第size個位置放新元素。因為size是 “當前已有的數量”,所以第size個位置正好是 “下一個空位置”。比如現在有 3 個元素(size=3),空位置就在索引 3 的位置,直接把新元素放進去。size++:放完之后,“已有的數量” 要加 1(比如原來 3 個,現在變成 4 個)。
LinkedList:
- 底層實現:基于
雙向鏈表
,每個節點(Node)包含prev(前驅)、next(后繼)指針和實際元素item。 - 源碼關鍵分析:插入 / 刪除效率高(無需移動元素),查詢需遍歷。
// 節點結構定義
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}
// 添加到尾部:直接修改尾節點的next指針
void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null) first = newNode;else l.next = newNode;size++;
}
HashMap
- 底層實現:基于
數組 + 鏈表 + 紅黑樹
,數組(Node<K,V>[] table)是主體,鏈表用于解決哈希沖突,當鏈表長度 > 8 且數組容量≥64 時轉為紅黑樹。 -
- 把
數組+鏈表+紅黑樹
的底層核心結構可以想象成一個帶編號的多層貨架:
- 把
-
- 第一層:
數組(哈希表,Node<K,V>[] table)
。這是最基礎的“大格子”,每個格子有唯一編號(索引),默認初始容量是16(必須是2的冪次,比如16、32、64…)。每個格子里可以放“鏈條”或“小數”。
- 第一層:
-
- 第二層:
鏈表(解決哈希沖突)
。當多個“商品”(key-value)計算后落到同一個“大格子”里時,會像串珠子一樣練成鏈表(每個節點Node有next指針,指向后一個節點)。
- 第二層:
-
- 第三層:
紅黑樹(優化長鏈表查詢)
。當一個格子里的鏈表太長(默認超過8個節點),且整個貨架的大格子數量>=64時,鏈表會自動轉成紅黑樹(一種平衡二叉樹)。樹的查詢效率比長鏈表高很多(從O(n)降到O(logn))。
- 第三層:
- 哈希計算:通過
(key.hashCode() ^ (key.hashCode() >>> 16))
擾動哈希值,再用(n-1) & hash
計算數組索引(n 為數組容量)。 - 哈希沖突:也叫哈希碰撞,是哈希表(如 HashMap)在存儲數據時必然可能遇到的問題。根本原因是哈希函數的 “輸出范圍”(數組索引的數量)是有限的,但 “輸入范圍”(可能的 key 數量)是無限的。比如數組長度只有 16(索引 0~15),但可能的 key 可以是 “蘋果”“橙子”“西瓜”…… 無數個,有限的索引必然會被無限的 key “重復占用”,沖突無法完全避免,只能盡量減少。
- 擴容機制:容量為 2 的冪次,擴容時通過
resize()
方法將元素重新哈希分配,紅黑樹可能拆分為鏈表。 - 關鍵代碼:
// 計算哈希值(減少碰撞)
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// 樹化判斷(JDK 1.8新增)
if (binCount >= TREEIFY_THRESHOLD - 1) // TREEIFY_THRESHOLD = 8treeifyBin(tab, hash);
HashSet
- 底層實現:基于HashMap,元素存儲在HashMap的key中,value固定為一個靜態常量(PRESENT = new object()).
- 特點:無序、不可重復,依賴HashMap的key去重(通過hashCode()和equals()判斷)。
-
無序
:元素的存儲順序不固定,因為HashMap的key是無序的;
-
去重
:依賴HashMap的key不重復(靠hashCode()和equals()判斷
);
-
線程不安全
:和HashMap一樣,多線程操作可能出問題;
-
查詢/增刪效率高
:平均時間復雜度是O(1),因為HashMap的核心操作效率高。
- HashSet里,不同元素可能算出相同哈希值(比如“蘋果”和“橙子”哈希值都是123),這是必須要再用equals()確認“到底是不是真的相同”,避免把“不同元素誤判為重復”。必須同時滿足兩個條件:
-
a.hashCode() == b.hashCode()
:兩個元素的哈希值相等(哈希值是元素的“數字身份證”,由hashCode()方法計算);
-
a.equals(b) == true
:兩個元素通過equals()方法比較,結果為“相等”。
- 關鍵代碼:
// 添加元素實際調用HashMap的put()
public boolean add(E e) {return map.put(e, PRESENT) == null; // 若key不存在則添加,返回true
}
// HashMap 的 put 方法有個規則:如果 key 不存在,就新增 key-value,返回 null;如果 key 已存在,就覆蓋 value,返回 “舊的 value”;
//所以 HashSet 的 add 方法:如果返回 true,說明 “元素是新的,添加成功”;如果返回 false,說明 “元素已存在,添加失敗”—— 這就實現了 “去重”。
總結
ArrayList
添加元素時,會先通過 ensureCapacityInternal 檢查容量夠不夠,不夠就擴容;夠的話直接把元素放到數組的末尾(elementData [size] 的位置),然后把元素數量 size 加 1。LinkedList
底層是雙向鏈表,每個節點存前后指針和元素。增刪快(改指針即可,不用挪元素),查詢慢(得從頭 / 尾遍歷)。適合頻繁增刪、少查詢的場景,和 ArrayList(數組,查快增刪慢)互補。HashMap
靠 “數組 + 鏈表 + 紅黑樹” 的結構,結合哈希計算和動態擴容,實現了高效的鍵值對存儲。核心特點是:查詢、增刪效率高(平均 O (1)),key 不重復(依賴hashCode()和equals()),線程不安全,適合頻繁查詢和修改的場景。HashSet
底層基于 HashMap 實現,把要存的元素作為 HashMap 的 key,用一個固定對象當 value,借 HashMap 的 key 去重特性實現自己的功能,特點是無序、不重復、效率高。