數據結構學習基礎和從包裝類緩存到泛型擦除的避坑指南

目錄

1.數據結構的概念和算法

1.1 數據結構的概念?

1.2 數據結構的集合框架

1.3 算法?

?1.3.1 時間復雜度

1.3.2 空間復雜度?

?2.包裝類

2.1 為什么需要包裝類?

?2.2 裝箱和拆箱

?3. 初識泛型

?3.1 認識泛型

3.2 泛型類的使用?

3.3 泛型的編譯

3.4 通配符

?3.4.1 無界通配符

3.4.2 上界通配符?

3.4.3 下界通配符?


1.數據結構的概念和算法

1.1 數據結構的概念?

數據結構是程序的骨架,算法是程序的靈魂。什么是數據結構?

在《大話數據結構》這本書中,作者指出:數據結構是相互之間存在一種或多種特定關系的數據元素的集合。也就是說,數據結構是計算機中存儲、組織數據的方式。就像現實生活中我們使用文件夾整理文檔、用書架分類書籍一樣,程序也需要合理的方式管理數據。

1.2 數據結構的集合框架

數據結構的主要集合框架為上圖。

學習數據結構,就要了解以上集合框架圖的關系和每個具體的類是什么樣的數據結構。這個圖做一個簡單的了解即可,不必刻意深記,在后面的學習中都會詳細介紹。

1.3 算法?

?算法是解決特定問題求解步驟的描述,在計算機中表現為指令的有限序列,并且每條指令表示一個或多個操作。

怎么衡量一個算法的好壞?這就要談到算法的效率。算法的效率分為兩種,一是時間效率,也稱為時間復雜度,二是空間效率,也稱為空間復雜度。二者通常用大O的漸進表示法來計算。

?1.3.1 時間復雜度

時間復雜度(Time Complexity)?是衡量算法執行時間隨輸入規模增長的變化趨勢的指標。它不計算具體的運行時間,而是描述算法在最壞或平均情況下執行基本操作的次數與輸入規模?n?的關系,通常用?大O符號(Big-O Notation)?表示。?

?大O漸進法怎么表示?

  1. 用常數 1 代替運行時間中的所有加法常數?
  2. 保留最高項,并且忽略最高項的系數

?怎么理解大O漸進表示?

通常在衡量一個算法的效率時,都是根據最壞情況去衡量。當然會有一些算法存在平均情況和最后情況。

最壞情況:任意輸入規模的最大允許次數

平均情況:任意輸入規模的期望運行次數

最壞情況:任意輸入規模的最小運行次數?

比如在一個長度為n的整數?升序?數組中,查找數組中是否存在某一個值時,如果按照線性查找的方式(從前到后或者從后到前)查找,那么最壞的可能是最后一個數組元素才是需要查找的值,或者這個數組本身就沒有這個值的時候,其時間復雜度便是達到?O(n) ,如果第一個元素就是要查找的值,這個時候就可以達到0(1) 。如果使用二分查找的方式(每次取這個數組的中間元素進行比較)進行查找,如果中間元素的值大于需要查找的值,則說明要查找的值在這個中間元素的左邊,那么下次查找只需要在左邊進行查找,依次類推,直到找到與需要查找的值相等或者最后一個元素為止,?這種方式時間復雜度最壞情況只有, 同理,如果第一個元素就是要查找的值,這個時候就可以達到0(1) 。

1.3.2 空間復雜度?

?空間復雜度(Space Complexity)是衡量算法在運行過程中?臨時占用的內存空間?隨輸入規模(n)增長的變化趨勢。與時間復雜度類似,空間復雜度也用?大O表示法(Big-O Notation)?描述。

有一些說法是:空間復雜度就是計算變量的個數?。

這個說法并不完全正確,空間復雜度計算的是?算法運行過程中額外占用的內存空間,而不僅僅是變量的個數。變量個數是影響因素之一,還需考慮:

  1. 變量的規模(如數組、鏈表、遞歸棧等占用的空間與輸入規模?n?相關)。

  2. 數據結構的內存占用(如?HashMap?比?Array?更占空間)。

  3. 遞歸調用的棧空間(每次遞歸都會占用額外的棧幀)。

比如曾經在遞歸的學習中,計算第 n 項的斐波那契數時,當項數達到一定值時,就會發生棧溢出。這是因為每一次遞歸時,都會產生一個臨時的內存空間來存儲參數和返回地址等。

?2.包裝類

2.1 為什么需要包裝類?

在Java中,由于基本類型并不是繼承 Object 類,為了在泛型代碼中可以支持基本類型,Java為8種基本數據類型提供的對應的引用類型(對象類型),用于將基本類型“包裝”成對象。其基本數據類型?的對應的包裝類如下:

?

?可以看出,出來 int char 的包裝類分別對應 Integer Character ,其余的基本數據類型對應的包裝類都是首字母大寫。

那么,為什么需要包裝類呢?

1. Java是面向對象的語言,但是基本數據類型并不是對象。包裝類的作用:

  • 存儲在集合中:如?List<Integer>(集合只能存對象,不能存基本類型)

  • 調用對象方法:如?Integer.parseInt(String s)

  • 支持泛型:泛型類型必須為對象(如?ArrayList<Integer>),而 ArrayList<int> 是錯誤的

如果沒有包裝類,就無法使用?ArrayListHashMap?等集合存儲基本類型。

2. 允許null

基本類型不能為null,但包裝類可以表示數據缺失或未初始化。

3. 提供豐富的工具方法

Integer.toBinaryString() ,可以把一個 int 類型的數據轉為二進制字符串,Character.isLetter() ,判斷一個字符是否為字母等

4. 自動裝箱和拆箱

?2.2 裝箱和拆箱

  • 裝箱(Boxing:將基本數據類型轉換為對應的包裝類對象。分為手動裝箱自動裝箱

public class Main {public static void main(String[] args) {int a = 10;//裝箱操作--手動裝箱Integer A11 = Integer.valueOf(a);Integer A12 = new Integer(a);//這種創建新對象已經過時,但是可以用//裝箱操作--自動裝箱Integer A21 = a;}
}
  • 拆箱(Unboxing:將包裝類對象轉換回基本數據類型。分為手動拆箱自動拆箱

public class Main {public static void main(String[] args) {Integer a = 10;//拆箱操作--手動拆箱int A = a.intValue();////拆箱操作--自動拆箱int B = a;//編譯器自動轉換}
}

注意事項:

1. 前面提到包裝類允許有 null ,但是如果把包裝類換成基本類型時,就會拋出異常NullPointerException?

2.?部分包裝類(如Integer)緩存?-128 ~ 127?的值,超出范圍會新建對象:?

?觀察以下代碼:

public class Main {public static void main(String[] args) {Integer a = 100;Integer b = 100;Integer c = 200;Integer d = 200;System.out.println(a == b);//結果1:System.out.println(c == d);//結果2:System.out.println(a.equals(b));//結果3:System.out.println(c.equals(d));//結果4:}
}

?輸出結果:

?為什么 c 和 d 都等于200時,輸出結果卻是 false呢?這是因為Java 對?Integer?包裝類設計了緩存機制(范圍默認是?-128~127 ),當超出這個范圍后,就會 new 一個新的對象,而對于對象的比較,不能用 == ,要用?equals() 或者對其拆箱再用 == 進行比較。

?3. 初識泛型

?3.1 認識泛型

關于泛型的概念,在《Java編程思想》中這樣介紹:一般的類和方法,只能使用具體的類型,要么是基本類型,要么是自定義的類。如果要編寫可以應用于多種類型的代碼,這種刻板的限制對代碼的束縛就會很大。也就是說,泛型的出現,是為了適用于許多種的類型。

當需要什么樣的類型時,就傳遞什么類型即可,包括 Integer、Character 等,也可以是自定義的類,使用泛型,可以在編譯時檢查類型匹配,避免運行時發生異常?ClassCastException

語法:

class? 泛型名稱 <類型形參列表> {

? ? ? ?//使用的類型參數

}?

比如在實現一個通用的哈希桶(在后面會學習到)時,就可以有以下代碼:

public class HashBuck<K,V> {static class Node<K, V> {public K key;public V val;public Node<K, V> next;public Node(K key , V val) {this.key = key;this.val = val;}}//往后實現具體方法等....
}

?泛型類用尖括號 <類型形參列表> 來表示,類型形參一般用大寫字母表示,常用的名稱有:

  • E:表示Element
  • K:表示Key
  • V:表示Value
  • N:表示Number
  • T:表示Type

3.2 泛型類的使用?

語法 :

泛型類<類型實參> 變量名;//定義一個泛型類引用

new 泛型類<類型實參>(構造方法實參);//實例化一個泛型類對象,實例化的泛型實參和構造方法可以沒有??

?泛型類也是一個類,在使用泛型時要 new 一個新的對象。如

ArrayList<Integer> list = new ArrayList<>();

3.3 泛型的編譯

?Java 泛型的核心在于編譯時的類型檢查運行時的類型擦除

類型擦除的原則(和繼承類似):

  • 無邊界類型參數

? ? ? ? 對于沒有邊界的泛型類(如<T>),在編譯時都會默認上界是 Object 類,也就是上 T 全部變為Object ,因為 Object 類?是所有類的父類

  • 有上界的類型參數

? ? ? ? 對于有上界的泛型類(如T? extends? Numbers),編譯時 T 會替換成 Number。

  • 泛型方法

? ? ? ? 編譯后,方法簽名中的?<T>被移除,參數和返回值的T替換為Object或上界。

// 源碼(編譯前)
public class Box<T> {private T value;public void set(T value) {this.value = value;}public T get() {return value;}
}// 字節碼(編譯后,等效代碼)
public class Box {private Object value; // T被擦除為Objectpublic void set(Object value) {this.value = value;}public Object get() {return value;}
}

?因此,List<String>和?List<Integer>的類對象是相同的,因為類型擦除,編譯后<String><Integer>)將被替換為原始類型(Object?或指定的上界類型),運行時均為List.class

3.4 通配符

?通配符(?)是 Java?泛型中的一種特殊語法,用于增強泛型的靈活性,主要解決泛型類型在繼承關系、未知類型、可以接收所有的泛型類型但又不希望他人隨意修改場景下的匹配問題。

?3.4.1 無界通配符<?>

表示未知類型,可以匹配任何的泛型類型,當方法需要接受任意類型的泛型對象但不關心具體類型時使用。

3.4.2 上界通配符?<? extends T>?

表示T?或其子類,用于放寬泛型的讀取限制?,當需要從泛型對象中安全讀取數據,且數據是?T?的子類時使用。

3.4.3 下界通配符?<? super T>?

表示T?或其父類,用于放寬泛型的寫入限制,當?需要向泛型對象中安全寫入數據,且數據是?T?的父類。

何時使用上界/下界通配符?

  • 需要讀取數據時用?<? extends T>

  • 需要寫入數據時用?<? super T>

  • 既讀又寫時用具體類型參數?<T>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91825.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡安全基礎知識【6】

什么是防火墻1.防火墻指的是一個由軟件和硬件設備組合而成、在內部網和外部網之間、 專用網與公共網之間的界面上構造的保護屏障 2.防火墻實際上是一種隔離技術 3.防火墻重要的特征是增加了區域的概念防火墻的定義 隔離可信與不可信網絡的設備/軟件&#xff0c;基于策略控制流量…

Apache Doris數據庫——大數據技術

Apache Doris一、簡介1.1、Apache Doris簡介1.2、Apache Doris 與傳統大數據架構相比1.3、doris是java團隊掌控大數據能力最優選擇1.4、 OLTP&#xff08;在線事務處理&#xff09; 與 OLAP&#xff08;在線分析處理&#xff09;1.5、發展歷程1.6、應用現狀1.7、整體架構1.7.1、…

Conda和pip的使用記錄

Conda和pip的使用記錄一、創建新的 Conda 環境二、激活環境三、安裝其他包&#xff08;可選&#xff09;四、查看已有環境五、刪除環境&#xff08;可選&#xff09;?? Conda 下載緩慢的解決方案&#xff08;推薦使用國內鏡像&#xff09;&#x1f527; 方法一&#xff1a;**…

詳解Python標準庫之互聯網數據處理

詳解Python標準庫之互聯網數據處理 在互聯網時代&#xff0c;數據的產生、傳輸和處理無處不在。從電子郵件的收發到 API 接口的數據交換&#xff0c;從二進制數據的編碼到 MIME 類型的識別&#xff0c;Python 標準庫提供了一整套強大的工具集&#xff0c;幫助開發者輕松應對各種…

適 配 器 模 式

前陣子&#xff0c;筆者在網上淘來一個二手顯示屏來搭配我裝好的主機&#xff0c;但是送到手上后我卻找不到電源適配器的蹤跡。于是我就在家找了根電源線接上了顯示屏&#xff0c;倒是能亮&#xff0c;就是屏幕閃得和機關槍似的。這是因為我的顯示屏需要12V的供電&#xff0c;我…

智慧零售商品識別準確率↑32%:陌訊多模態融合算法實戰解析

原創聲明本文為原創技術解析&#xff0c;核心技術參數與架構設計引用自《陌訊技術白皮書》&#xff0c;禁止任何形式的未經授權轉載。一、行業痛點&#xff1a;智慧零售的 "看得見的障礙"在智慧零售場景中&#xff0c;從自助結算終端到智能貨架管理&#xff0c;計算機…

Linux系統編程-gcc(黑馬筆記)

1 gcc的編譯流程gcc編譯的整個過程并且整個過程下來的每個過程。并且給出了每個階段產物和gcc命令。1.1 數據段合并其實就是因為“塊” 一次是讀多個字節而不是一個字節&#xff0c;所以會將一些地址段合并從而提升效率1.2 地址回填這張圖也有些問題&#xff0c;正確的結論是:地…

Git踩坑

文章目錄前言?問題分析&#xff1a;為什么你的提交會“覆蓋”別人的代碼&#xff1f;? 正確的代碼提交流程&#xff08;結合你原文的說明&#xff09;**1. 確認自己在正確的分支上****2. 從主開發分支&#xff08;如 dev&#xff09;拉取最新代碼并合并****3. 解決沖突&#…

sqli-labs:Less-20關卡詳細解析

1. 思路&#x1f680; 本關的SQL語句為&#xff1a; $sql"SELECT * FROM users WHERE username$cookee LIMIT 0,1";注入類型&#xff1a;字符串型&#xff08;單引號包裹&#xff09;、GET操作提示&#xff1a;參數需以閉合關鍵參數&#xff1a;cookee php輸出語句…

基于LevitUnet的超聲圖像分割

完整項目包獲取&#xff1a;點擊文末名片本項目旨在開發一個基于深度學習的圖像分割模型&#xff0c;專門用于處理醫學或遙感領域的圖像數據&#xff08;以 TIFF 格式存儲&#xff09;。通過結合 LeViT&#xff08;基于 Vision Transformer 的輕量模型&#xff09;和 U-Net 架構…

Java 17 新特性解析與代碼示例

Java 17 新特性解析與代碼示例 文章目錄Java 17 新特性解析與代碼示例引言1. 密封類&#xff08;JEP 409&#xff09;1.1. 介紹1.2. 詳細說明1.3. 代碼示例1.4. 與之前功能的對比1.5. 使用場景1.6. 總結2. switch 模式匹配&#xff08;預覽&#xff0c;JEP 406&#xff09;2.1.…

SQL中的GROUP BY用法

GROUP BY 是 SQL 中用來“按列分組”的子句。 它把相同值的行分到同一個組&#xff0c;然后通常配合聚合函數&#xff08;COUNT, SUM, AVG, MAX, MIN 等&#xff09;對每個組做統計&#xff0c;最終每組只返回一行結果。? 1. 基本語法 SELECT 列1, 列2, 聚合函數(列3) FROM 表…

AI Agent開發學習系列 - LangGraph(10): 帶有循環的Looping Graph(練習解答)

在AI Agent開發學習系列 - LangGraph(9): 帶有循環的Looping Graph中&#xff0c;我們學習了如何創建帶有循環的Looping Graph。為了鞏固學習&#xff0c;我們來做一個練習。 用LangGraph創建如下圖的一個Agent: 要求&#xff1a; 輸入玩家姓名通過輸入的上限值和下限值之間…

【保姆級 - 大模型應用開發】DeepSeek R1 本地部署全攻略:Ollama + vLLM + PyTorch 多選方案

DeepSeek R1 本地部署全攻略&#xff1a;Ollama vLLM PyTorch 多選方案 想部署 DeepSeek-R1 模型到本地&#xff0c;開啟高性能推理體驗&#xff1f;本文匯總了 Ollama、vLLM 及原生 PyTorch 的部署方法&#xff0c;適合不同開發者需求。 &#x1f3af; 下載模型 (必做) ----…

使用 Vive Tracker 替代 T265 實現位姿獲取(基于 Ubuntu + SteamVR)

在Dexcap這篇工作列出第二版硬件清單時&#xff0c;我注意到其使用 Vive Tracker 替代 Intel T265 來獲取位姿數據&#xff0c;對這個東西的性能感到好奇&#xff0c;最近因為需要跟進相關工作&#xff0c;參與了一部分實現&#xff0c;由于這方面的中文資料相對較少&#xff0…

博物館 VR 導覽:圖形渲染算法+智能講解技術算法實現及優化

本文面向博物館數字化開發技術員、VR 系統工程師等技術同仁們&#xff0c;聚焦圖形渲染算法在博物館 VR 導覽中的核心應用&#xff0c;解決虛擬展館還原精度不足、多終端適配卡頓、智能講解觸發延遲等實際技術問題。如有項目合作及技術交流歡迎私信作者~一、VR導覽技術痛點1.3D…

zset 中特殊的操作

首先 zset 與我們常規的 redis 操作有所不同, 這里的時間復雜度基本都是 O(log N) 起步的 目錄 1. zcount 2. zpopmax 1. zcount zcount key min max : 這里求的是 key 中下標在 min 和 max 之間的 元素的數量, 這里是比區間 我們要是想排除端點, 就需要加上 ( , 無論是…

KSP與ASM深度對比:原理、性能與使用場景

一、核心目的差異1. KSP&#xff08;Kotlin Symbol Processing&#xff09;核心目的&#xff1a;在編譯時生成新代碼&#xff0c;解決樣板代碼問題(操作對象:.kt源文件編譯過程中的中間表示)主要場景&#xff1a;自動生成DI&#xff08;依賴注入&#xff09;配置代碼創建路由映…

【LLM】如何在Cursor中調用Dify工作流

這篇文章將通過一個接口文檔知識庫示例&#xff0c;帶你了解如何在 Cursor 中通過 Mcp Server 調用 Dify 平臺配置的工作流。 1. 準備工作 需要準備文本生成模型、向量模型、Rerank 模型&#xff08;可選&#xff09;&#xff0c;這些都可以在 阿里云百煉平臺 申請免費使用額度…

L1、L2正則化的幾何解釋

L2正則化: 圖中用幾何方式形象地解釋了 Ridge 回歸&#xff08;L2正則化&#xff09;的原理。 ① 陰影圓&#xff1a;可以理解為&#xff08;w1^2 w2^2&#xff09;?≤R^2&#xff0c;圓周表示目標函數的約束線&#xff0c;這個圓表示了我們的參數 (w1,w2)可以活動的范圍。 …