Java常用工具類

異常 (Exception)。程序世界并非總是完美的,異常處理機制就是Java為我們提供的優雅應對錯誤的解決方案。


一、為什么需要異常處理?—— 從現實世界說起

想象一下現實生活中的場景:

  1. 開車上班:你計劃開車去公司(正常流程)。
    • 但可能遇到異常情況:爆胎、沒油、交通事故。
    • 你不會因此就停在路中間,而是有應對措施:換備胎、呼叫救援、聯系保險和交警。
  2. 網上購物:你提交訂單(正常流程)。
    • 但可能遇到異常情況:庫存不足、網絡斷開、支付失敗。
    • 網站不會直接崩潰,而是會給你友好的提示:“庫存不足”、“網絡異常,請重試”。

程序中的問題
在程序中,同樣充滿了各種意外:

  • 用戶輸入了錯誤格式的數據。
  • 要打開的文件不存在。
  • 網絡連接突然中斷。
  • 數據庫服務宕機。
  • 算術運算除以0。

沒有異常處理的傳統做法(C語言風格):
使用方法的返回值來表示錯誤狀態(如返回 -1null 等)。這會導致:

  1. 代碼臃腫:正常的業務邏輯和錯誤處理代碼混雜在一起,可讀性差。
  2. 容易遺漏:程序員可能忘記檢查返回值。
  3. 傳遞麻煩:錯誤信息需要一層層手動傳遞回調用者。

Java的解決方案:異常機制
Java使用 “拋出(Throw)-捕獲(Catch)” 模型。當錯誤發生時,方法會立即拋出(throw) 一個代表該錯誤的對象(異常對象),然后由專門的代碼塊來捕獲(catch) 并處理它。這使得正常邏輯和錯誤處理邏輯分離,代碼更加清晰和健壯。


二、Java異常體系結構

Java將所有的異常和錯誤封裝成了類,形成了一個清晰的繼承體系。Throwable 類是所有錯誤和異常的頂級父類。

text

        Throwable/    \/      \Error       Exception/   \/     \RuntimeException   IOException, SQLException, ...(unchecked)         (checked)
1. Error (錯誤)
  • 描述:指程序無法處理的嚴重問題,通常是JVM內部的錯誤或系統資源耗盡。
  • 特點:應用程序不應該試圖捕獲和處理這類錯誤。
  • 舉例
    • OutOfMemoryError:內存溢出。
    • StackOverflowError:棧溢出。
    • VirtualMachineError:虛擬機錯誤。
2. Exception (異常)

指程序本身可以捕獲和處理的問題。它分為兩大類:

  • Checked Exception (受檢異常)
    • 描述:除了 RuntimeException 及其子類以外的所有 Exception 子類。
    • 特點編譯器會檢查它。如果一個方法可能拋出受檢異常,必須在方法簽名上用 throws 聲明,或者方法內部用 try-catch 捕獲處理。否則,代碼無法通過編譯。
    • 舉例
      • IOException:IO操作異常。
      • SQLException:數據庫操作異常。
      • ClassNotFoundException:類找不到異常。
      • FileNotFoundException:文件找不到異常。
  • Unchecked Exception (非受檢異常 / 運行時異常)
    • 描述RuntimeException 類及其所有子類。
    • 特點編譯器不強制要求處理。程序可以選擇捕獲處理,也可以不處理。這些異常通常是由程序邏輯錯誤引起的,應該在代碼開發階段盡量避免。
    • 舉例
      • NullPointerException:空指針異常。
      • ArrayIndexOutOfBoundsException:數組下標越界異常。
      • ArithmeticException:算術異常(如除以0)。
      • ClassCastException:類型轉換異常。
      • IllegalArgumentException:非法參數異常。

簡單記憶

  • Error:搞不定,別處理。
  • Exception:能搞定,要處理。
    • Checked:不處理編譯就報錯
    • Unchecked:不處理運行才報錯

三、異常處理的關鍵字與機制

Java通過五個關鍵字來處理異常:try, catch, finally, throw, throws

1. 捕獲異常:try-catch-finally

這是處理異常的核心結構,用于捕獲和處理方法內部可能發生的異常。

  • try:包裹可能會發生異常的代碼。后面必須跟一個或多個 catch 塊或一個 finally 塊。
  • catch:捕獲并處理特定類型的異常。可以有多個 catch 塊,用于處理不同類型的異常。
  • finally無論是否發生異常,都會執行的代碼。通常用于釋放資源(如關閉文件、數據庫連接等)。

基本語法

java

try {// 可能會發生異常的代碼FileInputStream fis = new FileInputStream("nonexistent.txt");
} catch (FileNotFoundException e) {// 捕獲并處理FileNotFoundException異常System.out.println("文件找不到: " + e.getMessage());e.printStackTrace(); // 打印異常的堆棧跟蹤信息(非常有用 for debugging)
} catch (IOException e) { // 可以捕獲多個更具體的異常,父類異常要寫在后面System.out.println("發生IO異常");
} catch (Exception e) {// 捕獲所有其他異常(兜底)System.out.println("發生未知異常");
} finally {// 無論是否發生異常,都會執行的代碼System.out.println("finally塊始終執行");// 這里可以寫關閉資源的代碼,即使try塊中發生異常,資源也能被釋放
}

catch 的匹配順序

  • 從上到下進行匹配,一旦匹配成功,后面的 catch 塊就不會再執行。
  • 必須將更具體(子類)的異常放在前面,更通用(父類)的異常放在后面。否則,子類的 catch 塊將永遠無法被執行,導致編譯錯誤。
2. 拋出異常:throwthrows
  • throw:用在方法內部主動拋出一個異常對象(new 一個異常對象)。

    java

    public void setAge(int age) {if (age < 0 || age > 120) {// 主動拋出一個運行時異常throw new IllegalArgumentException("年齡不合法: " + age);}this.age = age;
    }
    
  • throws:用在方法聲明處聲明該方法可能拋出的受檢異常。調用此方法的代碼必須處理這些異常(要么繼續 throws,要么 try-catch)。

    java

    // 該方法聲明它可能拋出FileNotFoundException和IOException
    public void readFile() throws FileNotFoundException, IOException {FileInputStream fis = new FileInputStream("a.txt");// ... 讀寫操作fis.close();
    }
    

四、異常處理的最佳實踐與流程

1. 異常處理流程
  1. 程序執行 try 塊中的代碼。
  2. 如果 try 塊中發生異常,異常對象被拋出。
  3. JVM中止當前 try 塊的執行,開始檢查各個 catch 塊。
  4. 找到第一個能匹配該異常類型的 catch 塊并執行。
  5. 執行 finally 塊中的代碼(如果有)。
  6. 繼續執行 try-catch-finally 結構之后的代碼。

如果異常沒有被捕獲,它會沿著調用棧向上傳遞,如果一直傳遞到 main 方法仍未被處理,JVM會終止程序并打印異常的堆棧跟蹤信息。

2. 最佳實踐
  1. 具體明確:盡量捕獲具體的異常,而不是簡單地用 catch (Exception e) 一網打盡。

  2. 勿吞異常:不要在 catch 塊中什么都不做(如只寫一個空塊或只打印)。這會將錯誤隱藏,給調試帶來巨大困難。

  3. 善用 finally:將釋放資源的代碼(關閉文件、連接、流等)放在 finally 塊中,確保資源總能被釋放。(JDK 7 的 try-with-resources 語句更好,后續會學)

  4. 早拋出,晚捕獲:在底層方法中,遇到無法處理的異常應盡早 throw 出去;在高層(如UI層或主邏輯層)統一進行 catch 和處理(如給用戶友好提示)。

  5. 異常轉譯:有時捕獲一個異常后,可以拋出一個對當前層更有意義的業務異常。

    java

    catch (SQLException e) {throw new DaoException("數據庫操作失敗", e); // 將原始異常e作為cause傳入
    }
    
  6. 文檔化:使用JavaDoc的 @throws 標簽為方法聲明它可能拋出的異常。


五、自定義異常

Java允許我們創建自己的異常類,通常用于表示特定的業務邏輯錯誤。

步驟

  1. 繼承自 Exception(受檢異常)或 RuntimeException(非受檢異常)。
  2. 通常提供兩個構造方法:一個無參構造,一個帶有詳細描述信息(String message)的構造方法。

示例:自定義一個“余額不足”的異常。

java

// 1. 繼承RuntimeException,定義為非受檢異常(業務上通常如此)
public class InsufficientBalanceException extends RuntimeException {// 2. 提供構造方法public InsufficientBalanceException() {super();}public InsufficientBalanceException(String message) {super(message); // 調用父類構造方法}// 也可以提供帶原因(cause)的構造方法public InsufficientBalanceException(String message, Throwable cause) {super(message, cause);}
}// 使用自定義異常
public void withdraw(double amount) {if (amount > balance) {throw new InsufficientBalanceException("當前余額" + balance + ",取款金額" + amount + "不足");}balance -= amount;
}

總結

Java的異常處理機制是編寫健壯、可靠應用程序的基石。

核心概念說明
體系結構Throwable -> Error / Exception -> Checked / Unchecked
處理機制try-catch-finally 用于捕獲,throw/throws 用于拋出
關鍵區別Checked異常必須處理,否則編譯不通過;Unchecked異常不強制。
finally作用無論是否異常,都執行,常用于釋放資源。
自定義異常繼承 ExceptionRuntimeException,用于表示特定業務錯誤。

包裝類 (Wrapper Class)。它是連接基本數據類型和對象世界的橋梁。

我將作為您的助手,帶您理解為什么需要包裝類,以及如何在實際開發中熟練地使用它們。


一、為什么需要包裝類?—— 從“對象”說起

Java是一個面向對象的語言,其核心操作都是基于對象(Object)的。然而,我們之前學習的八種基本數據類型(byte, short, int, long, float, double, char, boolean 卻不是對象。

這就帶來了一個矛盾和一些實際需求:

  1. 某些場景只能使用對象

    • 泛型:Java的泛型(如 ArrayList<>)要求類型參數必須是類類型,不能是基本數據類型。
    • 集合框架:像 ArrayList, HashMap 這些容器,它們只能存儲對象Object 的子類)。

    java

    // 錯誤!無法編譯,泛型不能使用基本類型
    // ArrayList<int> list = new ArrayList<int>();// 正確!必須使用包裝類
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(10); // 這里其實發生了自動裝箱
    
  2. 需要對象提供的功能

    • 基本數據類型只是一塊純粹的數據,沒有方法。
    • 而包裝類是類,內部提供了很多有用的靜態方法常量,可以方便地進行數據轉換、判斷、計算等。

    java

    int num = Integer.parseInt("123"); // 將字符串轉換為int
    int max = Integer.MAX_VALUE;       // 獲取int的最大值
    
  3. 需要表示“空”(null)的概念

    • 基本數據類型的變量總是有值的(即使默認值也是0或false)。
    • 而包裝類對象可以為 null,可以用來表示“數據缺失”或“尚未賦值”的狀態,這在數據庫查詢、JSON解析等場景中非常常見。

    java

    Integer score = null; // 可以表示“成績未知”
    // int score = null; // 編譯錯誤!基本類型不能為null
    

Java的解決方案
為每一種基本數據類型都設計了一個對應的“包裝類”,將這些基本類型“包裝”起來,使其具有對象的形態。


二、包裝類與基本類型的對應關系

八種基本數據類型都有其對應的包裝類,這些包裝類都在 java.lang 包下,因此無需手動導入。

基本數據類型包裝類
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

注意

  • IntegerCharacter 的類名是全稱,不是 IntChar
  • 除了 IntegerCharacter,其他包裝類的類名基本都是基本類型首字母大寫。

三、裝箱與拆箱 (Boxing & Unboxing)

“裝箱”和“拆箱”是操作包裝類的核心概念。

  • 裝箱 (Boxing):將基本數據類型轉換為對應的包裝類對象
  • 拆箱 (Unboxing):將包裝類對象轉換為對應的基本數據類型

在JDK 1.5之前,必須手動進行裝箱和拆箱,非常繁瑣。

1. 手動裝箱與拆箱 (JDK 1.5之前)

java

// 手動裝箱:基本類型 -> 包裝類對象
int num1 = 10;
Integer integerObj1 = Integer.valueOf(num1); // 方式一:推薦,可能用到緩存
// Integer integerObj2 = new Integer(num1);    // 方式二:已過時(Deprecated),不推薦// 手動拆箱:包裝類對象 -> 基本類型
Integer integerObj2 = Integer.valueOf(20);
int num2 = integerObj2.intValue(); // 調用xxxValue()方法// 其他類型類似
double d = 3.14;
Double doubleObj = Double.valueOf(d);
double d2 = doubleObj.doubleValue();char c = 'A';
Character charObj = Character.valueOf(c);
char c2 = charObj.charValue();
2. 自動裝箱與拆箱 (Autoboxing & Unboxing, JDK 1.5+)

從JDK 1.5開始,Java引入了自動裝箱自動拆箱的特性。編譯器在背后自動為我們添加上面的手動轉換代碼,極大地方便了開發。

  • 自動裝箱:可以直接將基本數據類型賦值給包裝類引用。
  • 自動拆箱:可以直接將包裝類對象賦值給基本類型變量,或者參與基本類型的運算。

java

// --- 自動裝箱 --- //
Integer a = 10; // 編譯器自動改為:Integer a = Integer.valueOf(10);
Double b = 3.14;
Character c = '嗨';
Boolean d = true;// --- 自動拆箱 --- //
int e = a; // 編譯器自動改為:int e = a.intValue();
double f = b;
char g = c;
boolean h = d;// 自動拆箱的常見場景:參與運算
Integer i = 100;
Integer j = 200;
int result = i + j; // 1. i和j先自動拆箱為int// 2. 然后進行 100 + 200 的加法運算// 3. 將結果300賦值給result// 在集合中使用(最常用的場景)
ArrayList<Integer> list = new ArrayList<>();
list.add(1);   // 自動裝箱:int -> Integer
list.add(2);
int first = list.get(0); // 自動拆箱:Integer -> int

注意:雖然自動裝箱拆箱很方便,但背后依然有方法調用(如 valueOf(), intValue())的開銷,在性能極度敏感的場景(如超大規模循環)中需要留意。


四、包裝類的常用操作與方法

包裝類提供了很多實用的靜態方法和成員方法。

1. 類型轉換
  • 字符串 -> 基本類型 / 包裝類:這是最常用的功能!

    java

    // String -> int
    String str = "123";
    int num = Integer.parseInt(str); // 核心方法:parseXxx(String s)// String -> double
    String str2 = "3.14";
    double d = Double.parseDouble(str2);// String -> boolean
    // ("true" -> true, 其他任何字符串 -> false)
    String str3 = "true";
    boolean b = Boolean.parseBoolean(str3);
    
  • 基本類型 / 包裝類 -> 字符串

    java

    int num = 456;
    // 方式一:最常用,字符串拼接(本質是String.valueOf())
    String str1 = "" + num;// 方式二:String類的valueOf()方法
    String str2 = String.valueOf(num);// 方式三:包裝類的toString()靜態方法
    String str3 = Integer.toString(num);// 方式四:包裝類對象的toString()方法
    Integer obj = 456;
    String str4 = obj.toString();
    
2. 常用常量與方法

java

// 常用常量
System.out.println(Integer.MAX_VALUE); // int最大值: 2147483647
System.out.println(Integer.MIN_VALUE); // int最小值: -2147483648
System.out.println(Double.NaN);        // 表示"非數字"
System.out.println(Double.POSITIVE_INFINITY); // 正無窮大// 比較方法
Integer x = 100;
Integer y = 100;
// 比較包裝對象的值
System.out.println(x.equals(y)); // true (推薦:比較值)
// 比較對象的引用地址(有坑!)
System.out.println(x == y);      // true? false? 下文詳解// 其他工具方法
System.out.println(Integer.bitCount(7)); // 計算二進制中1的個數 (7的二進制是111,輸出3)
System.out.println(Integer.toBinaryString(10)); // 轉二進制字符串: "1010"
System.out.println(Integer.toHexString(255));   // 轉十六進制字符串: "ff"

五、重要特性:包裝類的緩存機制

這是一個面試高頻考點易錯點

Java為了節省內存和提高性能,對部分包裝類對象實現了緩存。即在一定的數值范圍內,相同的值會返回同一個對象

  • Integer 緩存:默認緩存了 -128 到 127 之間的整數。
  • Byte, Short, Long 緩存:緩存范圍也是 -128 到 127
  • Character 緩存:緩存了 0 到 127 之間的字符(ASCII字符)。
  • Boolean 緩存:直接緩存了 TRUEFALSE 兩個對象。

緩存機制帶來的影響

java

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true (因為100在緩存范圍內,a和b是同一個對象)Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false (因為200不在緩存范圍內,c和d是new的兩個不同對象)// 正確的比較方式:始終使用.equals()方法來比較包裝類的值!
System.out.println(a.equals(b)); // true
System.out.println(c.equals(d)); // true

結論比較兩個包裝類對象的值是否相等,一定要使用 .equals() 方法,永遠不要使用 ==


六、總結與最佳實踐

特性說明
存在意義讓基本類型具備對象的特性,用于泛型、集合、表示null等場景。
自動裝箱Integer i = 10; (基本類型 -> 包裝類)
自動拆箱int n = i; (包裝類 -> 基本類型)
核心方法Integer.parseInt("123"), i.toString()
比較必須使用 i.equals(j),切勿使用 ==
緩存機制Integer 等緩存了-128到127的對象,== 在此范圍內可能為true。

最佳實踐

  1. 優先使用基本類型:在不需要對象的場景下(如局部變量、循環計數器),使用基本類型性能更好。
  2. 必要時刻使用包裝類:在泛型、集合、需要表示null值時,必須使用包裝類。
  3. 比較用 .equals():牢記包裝類比較值要使用 .equals() 方法。
  4. 警惕空指針異常 (NPE):包裝類對象可以為 null,自動拆箱時如果對象是 null,會拋出 NullPointerException
Integer possibleNull = null;
// int num = possibleNull; // 運行時拋出 NullPointerException
// 安全做法
if (possibleNull != null) {int num = possibleNull;
}

Java字符串(String)深度解析

作為您的Java開發助手,我將為您全面系統地梳理Java中最重要的類之一——字符串(String)。字符串處理是編程中最常見的任務,深入理解String類對成為優秀的Java開發者至關重要。

一、String類的重要性與特點

為什么String如此重要?

  • 字符串處理占日常Java開發的30%以上工作量
  • 幾乎所有應用都需要處理文本數據、用戶輸入、文件內容等
  • Java為字符串優化提供了特殊機制

String類的核心特點

  1. 不可變性(Immutability):String對象一旦創建,其值就不能被改變
  2. 字符串池(String Pool):Java使用字符串池優化內存使用
  3. final類:String類是final的,不能被繼承
  4. 實現了多個接口:Serializable, Comparable, CharSequence

二、String對象的創建方式

1. 直接使用字面量(推薦)

java

String str1 = "Hello World";  // 使用字符串池
String str2 = "Hello World";  // 重用字符串池中的對象
System.out.println(str1 == str2); // true,引用相同對象

2. 使用new關鍵字

java

String str3 = new String("Hello World");  // 強制創建新對象
String str4 = new String("Hello World");  // 創建另一個新對象
System.out.println(str3 == str4); // false,不同對象
System.out.println(str3.equals(str4)); // true,內容相同

3. 從字符數組創建

java

char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str5 = new String(charArray); // "Hello"

4. 從字節數組創建

java

byte[] byteArray = {72, 101, 108, 108, 111}; // ASCII碼
String str6 = new String(byteArray); // "Hello"

三、字符串池(String Pool)機制

什么是字符串池?

  • Java為了減少內存開銷而設計的特殊存儲區域
  • 存儲所有字符串字面量
  • 避免創建相同內容的重復字符串

字符串池工作原理

java

String s1 = "Java";        // 在池中創建
String s2 = "Java";        // 重用池中的對象
String s3 = new String("Java"); // 在堆中創建新對象System.out.println(s1 == s2);     // true,相同引用
System.out.println(s1 == s3);     // false,不同引用
System.out.println(s1.equals(s3)); // true,內容相同

intern()方法

java

String s4 = new String("Python").intern(); // 將字符串放入池中或返回池中的引用
String s5 = "Python";
System.out.println(s4 == s5); // true

四、字符串不可變性及其影響

不可變性的含義

java

String str = "Hello";
str.concat(" World"); // 返回新字符串"Hello World",但str仍然是"Hello"
System.out.println(str); // 輸出"Hello"// 正確的方式
String newStr = str.concat(" World");
System.out.println(newStr); // 輸出"Hello World"

不可變性的優點

  1. 安全性:字符串作為參數傳遞時不會被修改
  2. 線程安全:多個線程可以安全地共享字符串
  3. 哈希碼緩存:String的hashCode()方法會緩存結果,提高哈希表性能
  4. 字符串池實現基礎:只有不可變對象才能被安全地共享

不可變性的缺點

頻繁修改字符串時會產生大量臨時對象,影響性能:

java

// 低效的字符串拼接
String result = "";
for (int i = 0; i < 1000; i++) {result += i; // 每次循環都會創建新的StringBuilder和String對象
}

五、String類的常用方法

1. 獲取字符串信息

java

String str = "Hello Java";// 獲取長度
int len = str.length(); // 10// 獲取指定位置字符
char ch = str.charAt(1); // 'e'// 獲取字符數組
char[] chars = str.toCharArray();// 獲取子字符串
String sub1 = str.substring(6); // "Java"
String sub2 = str.substring(0, 5); // "Hello"

2. 字符串比較

java

String s1 = "Java";
String s2 = "java";
String s3 = "Java";// 區分大小寫比較
boolean b1 = s1.equals(s2); // false// 不區分大小寫比較
boolean b2 = s1.equalsIgnoreCase(s2); // true// 比較字符串順序
int result = s1.compareTo(s2); // 負數(s1 < s2)
int result2 = s1.compareToIgnoreCase(s2); // 0// 檢查前綴后綴
boolean starts = s1.startsWith("Ja"); // true
boolean ends = s1.endsWith("va"); // true

3. 字符串查找

java

String text = "Java is a programming language";// 查找字符/字符串位置
int index1 = text.indexOf('a'); // 1
int index2 = text.indexOf('a', 2); // 從位置2開始查找,返回3
int index3 = text.indexOf("programming"); // 10// 從后向前查找
int lastIndex = text.lastIndexOf('a'); // 22// 檢查是否包含
boolean contains = text.contains("Java"); // true

4. 字符串轉換

java

String str = "  Hello World  ";// 去除首尾空格
String trimmed = str.trim(); // "Hello World"// 大小寫轉換
String upper = str.toUpperCase(); // "  HELLO WORLD  "
String lower = str.toLowerCase(); // "  hello world  "// 替換字符/字符串
String replaced = str.replace('l', 'L'); // "  HeLLo WorLd  "
String replacedAll = str.replaceAll("l", "L"); // "  HeLLo WorLd  "// 分割字符串
String[] parts = "Java,Python,C++".split(","); // ["Java", "Python", "C++"]

六、字符串拼接性能優化

1. 使用StringBuilder(非線程安全,性能高)

java

// 高效的字符串拼接
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {sb.append(i);
}
String result = sb.toString();

2. 使用StringBuffer(線程安全,性能稍低)

java

// 線程安全的字符串拼接
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < 1000; i++) {sbf.append(i);
}
String result = sbf.toString();

3. Java 8+的String.join()

java

// 拼接字符串數組或集合
String[] words = {"Java", "Python", "C++"};
String result = String.join(", ", words); // "Java, Python, C++"List<String> list = Arrays.asList("Apple", "Banana", "Orange");
String result2 = String.join(" - ", list); // "Apple - Banana - Orange"

七、字符串與其它類型的轉換

1. 基本數據類型轉字符串

java

// 多種方式
String s1 = String.valueOf(123); // "123"
String s2 = String.valueOf(3.14); // "3.14"
String s3 = String.valueOf(true); // "true"
String s4 = 456 + ""; // "456" (不推薦,會產生臨時字符串)

2. 字符串轉基本數據類型

java

// 使用包裝類的parseXxx方法
int i = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
boolean b = Boolean.parseBoolean("true");// 處理可能出現的異常
try {int num = Integer.parseInt("123abc");
} catch (NumberFormatException e) {System.out.println("不是有效的數字格式");
}

八、正則表達式與字符串

1. 匹配模式

java

String email = "test@example.com";
boolean isValid = email.matches("^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");

2. 替換操作

java

String text = "My phone number is 123-456-7890";
// 隱藏電話號碼
String hidden = text.replaceAll("\\d{3}-\\d{3}-\\d{4}", "***-***-****");

3. 分割字符串

java

String csv = "Java,Python,C++,JavaScript";
String[] languages = csv.split(",\\s*"); // 按逗號分割,允許逗號后有空格

九、性能優化與最佳實踐

1. 優先使用字符串字面量

java

// 好
String s1 = "Hello";// 不好(除非確需新實例)
String s2 = new String("Hello");

2. 使用StringBuilder進行復雜拼接

java

// 好
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("World");// 不好(產生多個臨時對象)
String result = "Hello" + " " + "World"; // 編譯器會優化為StringBuilder,但復雜循環中仍需顯式使用

3. 使用equals()比較內容,==比較引用

java

String s1 = "Java";
String s2 = new String("Java");// 比較內容
boolean contentEqual = s1.equals(s2); // true// 比較引用
boolean referenceEqual = (s1 == s2); // false

4. 注意字符串編碼

java

// 指定編碼轉換
try {String str = "中文";byte[] utf8Bytes = str.getBytes("UTF-8");String newStr = new String(utf8Bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {e.printStackTrace();
}

十、Java 9+的字符串優化

1. 緊湊字符串(Compact Strings)

  • Java 9前:String使用char[]存儲,每個字符占2字節
  • Java 9+:根據字符串內容選擇Latin-1(1字節)或UTF-16(2字節)編碼
  • 減少內存占用,提高性能

2. 字符串拼接優化

Java 9+對字符串拼接進行了內部優化,但在復雜場景下仍建議使用StringBuilder。

Java集合框架(Collection Framework)全面解析

作為您的Java開發助手,我將為您系統性地梳理Java集合框架的知識。集合框架是Java中最重要、最常用的工具庫之一,幾乎在所有Java應用程序中都會用到。

一、為什么需要集合框架?

在編程中,我們經常需要存儲和操作一組對象。數組雖然可以存儲多個元素,但存在以下局限性:

  • 長度固定,無法動態擴展
  • 缺乏豐富的操作方法
  • 只能存儲相同類型的數據

集合框架解決了這些問題,提供了:

  1. 動態大小:集合可以動態增長和縮小
  2. 豐富API:提供了添加、刪除、查找、排序等豐富操作
  3. 類型安全:通過泛型保證類型安全
  4. 高性能:針對不同場景優化了數據結構

二、集合框架體系結構

Java集合框架主要由兩大接口組成:CollectionMap

1. Collection接口繼承體系

text

Collection (接口)
├── List (接口 - 有序、可重復)
│   ├── ArrayList (數組實現)
│   ├── LinkedList (鏈表實現)
│   └── Vector (線程安全的數組實現,已較少使用)
│       └── Stack (棧實現)
├── Set (接口 - 無序、不可重復)
│   ├── HashSet (哈希表實現)
│   │   └── LinkedHashSet (保持插入順序的HashSet)
│   ├── TreeSet (紅黑樹實現,有序)
│   └── EnumSet (枚舉專用Set)
└── Queue (接口 - 隊列)├── PriorityQueue (優先級隊列)├── LinkedList (也可作為隊列使用)└── Deque (接口 - 雙端隊列)├── ArrayDeque (數組實現的雙端隊列)└── LinkedList (鏈表實現的雙端隊列)

2. Map接口繼承體系

text

Map (接口)
├── HashMap (哈希表實現)
│   └── LinkedHashMap (保持插入順序的HashMap)
├── Hashtable (線程安全的哈希表,已較少使用)
│   └── Properties (配置專用)
├── TreeMap (紅黑樹實現,有序)
└── WeakHashMap (弱引用HashMap)

三、核心接口詳解

1. Collection接口

所有集合類的根接口,定義了基本操作:

java

boolean add(E e)           // 添加元素
boolean remove(Object o)   // 刪除元素
boolean contains(Object o) // 判斷是否包含
int size()                 // 獲取元素數量
boolean isEmpty()          // 判斷是否為空
Iterator<E> iterator()     // 獲取迭代器
void clear()               // 清空集合

2. List接口(有序、可重復)

  • 元素有順序(插入順序)
  • 可以通過索引訪問元素
  • 允許重復元素

3. Set接口(無序、不可重復)

  • 元素無順序(除非是TreeSet或LinkedHashSet)
  • 不允許重復元素
  • 最多包含一個null元素

4. Map接口(鍵值對)

  • 存儲鍵值對映射
  • 鍵不能重復(重復的鍵會覆蓋舊值)
  • 每個鍵最多映射到一個值

5. Queue接口(隊列)

  • 先進先出(FIFO)的數據結構
  • 支持在隊列兩端進行操作

四、主要實現類詳解

1. ArrayList

基于動態數組實現,是最常用的List實現。

java

// 創建ArrayList
List<String> list = new ArrayList<>();// 添加元素
list.add("Apple");
list.add("Banana");
list.add("Orange");// 訪問元素
String fruit = list.get(0); // "Apple"// 遍歷元素
for (String item : list) {System.out.println(item);
}// 使用索引遍歷
for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
}// 使用迭代器遍歷
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}// 使用forEach方法(Java 8+)
list.forEach(System.out::println);// 刪除元素
list.remove("Banana");
list.remove(0); // 按索引刪除// 判斷是否包含
boolean hasApple = list.contains("Apple");// 轉換為數組
String[] array = list.toArray(new String[0]);

特點

  • 隨機訪問快(O(1))
  • 在尾部添加元素快(O(1))
  • 在中間插入/刪除元素慢(需要移動元素,O(n))
  • 非線程安全

2. LinkedList

基于雙向鏈表實現,可用作List、Queue或Deque。

java

// 創建LinkedList
List<String> list = new LinkedList<>();
Queue<String> queue = new LinkedList<>();
Deque<String> deque = new LinkedList<>();// 作為List使用
list.add("A");
list.add("B");
list.get(1); // "B"// 作為Queue使用
queue.offer("A"); // 添加元素到隊列尾
queue.poll();     // 移除并返回隊列頭元素
queue.peek();     // 返回隊列頭元素但不移除// 作為Deque使用
deque.addFirst("A"); // 添加到隊列頭
deque.addLast("B");  // 添加到隊列尾
deque.removeFirst(); // 移除并返回隊列頭元素
deque.removeLast();  // 移除并返回隊列尾元素

特點

  • 在任意位置插入/刪除元素快(O(1))
  • 隨機訪問慢(需要遍歷,O(n))
  • 實現了List和Deque接口
  • 非線程安全

3. HashSet

基于哈希表實現,是最常用的Set實現。

java

// 創建HashSet
Set<String> set = new HashSet<>();// 添加元素
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Apple"); // 重復元素,不會被添加// 判斷是否包含
boolean hasApple = set.contains("Apple");// 刪除元素
set.remove("Banana");// 遍歷元素
for (String item : set) {System.out.println(item);
}// 獲取元素數量
int size = set.size();

特點

  • 添加、刪除、查找操作快(平均O(1))
  • 元素無序
  • 允許null元素
  • 非線程安全

4. LinkedHashSet

繼承自HashSet,保持元素的插入順序。

java

Set<String> set = new LinkedHashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");// 遍歷時會按照添加順序輸出
for (String fruit : set) {System.out.println(fruit); // Apple, Banana, Orange
}

特點

  • 保持插入順序
  • 性能略低于HashSet
  • 非線程安全

5. TreeSet

基于紅黑樹實現,元素有序。

java

// 創建TreeSet
Set<String> set = new TreeSet<>();// 添加元素(會自動排序)
set.add("Orange");
set.add("Apple");
set.add("Banana");// 遍歷時會按自然順序輸出
for (String fruit : set) {System.out.println(fruit); // Apple, Banana, Orange
}// 可以使用Comparator自定義排序
Set<String> customSet = new TreeSet<>(Comparator.reverseOrder());
customSet.add("Orange");
customSet.add("Apple");
customSet.add("Banana");for (String fruit : customSet) {System.out.println(fruit); // Orange, Banana, Apple
}

特點

  • 元素有序(自然順序或指定Comparator)
  • 添加、刪除、查找操作時間復雜度為O(log n)
  • 不允許null元素
  • 非線程安全

6. HashMap

基于哈希表實現,是最常用的Map實現。

java

// 創建HashMap
Map<String, Integer> map = new HashMap<>();// 添加鍵值對
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);// 獲取值
Integer count = map.get("Apple"); // 1// 判斷是否包含鍵
boolean hasApple = map.containsKey("Apple");// 判斷是否包含值
boolean hasValue = map.containsValue(1);// 遍歷鍵
for (String key : map.keySet()) {System.out.println(key);
}// 遍歷值
for (Integer value : map.values()) {System.out.println(value);
}// 遍歷鍵值對
for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}// 使用forEach方法(Java 8+)
map.forEach((k, v) -> System.out.println(k + ": " + v));// 刪除鍵值對
map.remove("Banana");// 獲取元素數量
int size = map.size();

特點

  • 基于哈希表,操作速度快(平均O(1))
  • 鍵無序
  • 允許null鍵和null值
  • 非線程安全

7. LinkedHashMap

繼承自HashMap,保持鍵的插入順序或訪問順序。

java

// 保持插入順序
Map<String, Integer> map = new LinkedHashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);// 遍歷時會按照插入順序輸出
for (String key : map.keySet()) {System.out.println(key); // Apple, Banana, Orange
}// 創建按訪問順序排序的LinkedHashMap(最近最少使用)
Map<String, Integer> lruMap = new LinkedHashMap<>(16, 0.75f, true);
lruMap.put("Apple", 1);
lruMap.put("Banana", 2);
lruMap.put("Orange", 3);lruMap.get("Apple"); // 訪問Apple,使其成為最近訪問的// 遍歷時會按訪問順序輸出(最近訪問的在最后)
for (String key : lruMap.keySet()) {System.out.println(key); // Banana, Orange, Apple
}

特點

  • 保持鍵的插入順序或訪問順序
  • 性能略低于HashMap
  • 非線程安全

8. TreeMap

基于紅黑樹實現,鍵有序。

java

// 創建TreeMap
Map<String, Integer> map = new TreeMap<>();// 添加鍵值對(按鍵的自然順序排序)
map.put("Orange", 3);
map.put("Apple", 1);
map.put("Banana", 2);// 遍歷時會按鍵的自然順序輸出
for (String key : map.keySet()) {System.out.println(key + ": " + map.get(key)); // Apple:1, Banana:2, Orange:3
}// 可以使用Comparator自定義排序
Map<String, Integer> customMap = new TreeMap<>(Comparator.reverseOrder());
customMap.put("Orange", 3);
customMap.put("Apple", 1);
customMap.put("Banana", 2);for (String key : customMap.keySet()) {System.out.println(key + ": " + map.get(key)); // Orange:3, Banana:2, Apple:1
}

特點

  • 鍵有序(自然順序或指定Comparator)
  • 操作時間復雜度為O(log n)
  • 不允許null鍵(但允許null值)
  • 非線程安全

五、集合的遍歷方式

1. 使用迭代器(Iterator)

java

List<String> list = new ArrayList<>();
// 添加元素...Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();System.out.println(element);// 可以在遍歷時安全刪除元素if (element.equals("RemoveMe")) {iterator.remove();}
}

2. 使用for-each循環(推薦)

java

for (String element : list) {System.out.println(element);// 注意:不能在for-each循環中直接刪除元素,會拋出ConcurrentModificationException
}

3. 使用forEach方法(Java 8+)

java

list.forEach(element -> System.out.println(element));
// 或使用方法引用
list.forEach(System.out::println);

4. 遍歷Map的幾種方式

java

Map<String, Integer> map = new HashMap<>();
// 添加鍵值對...// 1. 遍歷鍵
for (String key : map.keySet()) {System.out.println(key + ": " + map.get(key));
}// 2. 遍歷值
for (Integer value : map.values()) {System.out.println(value);
}// 3. 遍歷鍵值對(推薦)
for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}// 4. 使用forEach方法(Java 8+)
map.forEach((k, v) -> System.out.println(k + ": " + v));

六、集合工具類Collections

Collections類提供了許多操作集合的靜態方法:

1. 排序操作

java

List<Integer> list = Arrays.asList(3, 1, 4, 1, 5, 9);// 排序
Collections.sort(list);
System.out.println(list); // [1, 1, 3, 4, 5, 9]// 反轉排序
Collections.sort(list, Collections.reverseOrder());
System.out.println(list); // [9, 5, 4, 3, 1, 1]// 隨機打亂
Collections.shuffle(list);
System.out.println(list); // 隨機順序// 反轉列表
Collections.reverse(list);
System.out.println(list); // 反轉順序

2. 查找和替換操作

java

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);// 二分查找(必須先排序)
Collections.sort(list);
int index = Collections.binarySearch(list, 3); // 2// 查找極值
int max = Collections.max(list); // 5
int min = Collections.min(list); // 1// 替換所有
Collections.replaceAll(list, 1, 10);
System.out.println(list); // [10, 2, 3, 4, 5]// 填充
Collections.fill(list, 0);
System.out.println(list); // [0, 0, 0, 0, 0]

3. 同步包裝

將非線程安全的集合轉換為線程安全的版本:

java

List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());

七、集合的性能比較與選擇指南

集合類型實現類特點適用場景
ListArrayList隨機訪問快,增刪慢需要頻繁按索引訪問元素
LinkedList增刪快,隨機訪問慢需要頻繁在頭部/中間插入刪除元素
SetHashSet查找快,無序需要快速查找,不關心順序
LinkedHashSet查找快,保持插入順序需要快速查找且保持插入順序
TreeSet有序,查找較慢需要有序遍歷元素
MapHashMap查找快,無序需要快速鍵值查找,不關心順序
LinkedHashMap查找快,保持插入/訪問順序需要快速查找且保持順序
TreeMap有序,查找較慢需要有序遍歷鍵
QueueArrayDeque雙端隊列,高效需要隊列或棧功能
PriorityQueue優先級隊列需要按優先級處理元素

八、最佳實踐與注意事項

  1. 使用泛型:始終使用泛型指定集合元素類型,避免類型轉換錯誤

    java

    // 好
    List<String> list = new ArrayList<>();// 不好(會產生警告,可能運行時出錯)
    List list = new ArrayList();
    
  2. 使用接口類型聲明:使用接口類型聲明集合變量,提高代碼靈活性

    java

    // 好
    List<String> list = new ArrayList<>();
    Set<String> set = new HashSet<>();
    Map<String, Integer> map = new HashMap<>();// 不好(將實現綁定到具體類)
    ArrayList<String> list = new ArrayList<>();
    
  3. 預估初始容量:對于已知大小的集合,設置初始容量避免頻繁擴容

    java

    // 預估有1000個元素
    List<String> list = new ArrayList<>(1000);
    Map<String, Integer> map = new HashMap<>(1000);
    
  4. 注意線程安全:默認集合實現都不是線程安全的,多線程環境下需要同步

    java

    // 方式1:使用同步包裝
    List<String> syncList = Collections.synchronizedList(new ArrayList<>());// 方式2:使用并發集合(java.util.concurrent包)
    ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
    CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();
    
  5. 正確實現equals和hashCode:如果要將自定義對象作為HashMap的鍵或HashSet的元素,必須正確重寫equals()和hashCode()方法

    java

    public class Person {private String name;private int age;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
    }
    
  6. 使用Java 8+新特性:利用Stream API和Lambda表達式簡化集合操作

    java

    List<String> list = Arrays.asList("Apple", "Banana", "Orange", "Avocado");// 過濾并轉換
    List<String> result = list.stream().filter(s -> s.startsWith("A")).map(String::toUpperCase).collect(Collectors.toList());System.out.println(result); // [APPLE, AVOCADO]
    

九、總結

Java集合框架提供了豐富的數據結構和算法,是Java編程的核心組成部分。掌握集合框架的關鍵點包括:

  1. 理解體系結構:清楚Collection和Map兩大接口體系及其實現類
  2. 掌握常用實現類:熟練使用ArrayList、LinkedList、HashSet、HashMap等常用集合
  3. 正確選擇集合類型:根據需求特點選擇合適的集合實現
  4. 熟練操作集合:掌握集合的遍歷、排序、查找等操作
  5. 遵循最佳實踐:使用泛型、注意線程安全、正確實現equals/hashCode等

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

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

相關文章

AWS亞馬遜云賬號注冊指南

AWS是全球領先的云計算平臺&#xff0c;提供廣泛的云服務。賬號注冊是開端&#xff0c;不管是用來學習、搭建個人項目&#xff0c;還是公司項目部署上線需要&#xff0c;都需要進行這一步。提醒&#xff1a;在使用賬戶之前&#xff0c;必須要綁定國際的信用卡&#xff1b;通過我…

云計算學習100天-第31天

Keepalived概念keepalived 是Linux下一個輕量級的高可用解決方案主要是通過虛擬路由冗余協議(VRRP)來實現高可用功能Virtual Router Redundancy Protocol起初就是為了補充LVS功能而設計的&#xff0c;用于監控LVS集群內后端真實服務器狀態后來加入了VRRP的功能&#xff0c;它出…

2025年視覺、先進成像和計算機技術論壇(VAICT 2025)

會議簡介 作為人工智能大數據創新發展論壇的重要分論壇&#xff0c;2025年視覺、先進成像和計算機技術論壇聚焦人工智能感知世界的核心前沿&#xff0c;將于2025年9月18-20日在中國廣州廣東科學館舉行。 視覺與成像技術是智能系統理解環境的關鍵&#xff0c;計算機技術則…

MySQL 與 ClickHouse 深度對比:架構、性能與場景選擇指南

&#x1f31f; 引言&#xff1a;數據時代的引擎之爭 在當今數據驅動的企業環境中&#xff0c;選擇合適的數據庫引擎成為架構設計的關鍵決策。想象這樣一個場景&#xff1a;特斯拉的實時車況分析系統需要在毫秒級延遲下處理數百萬輛汽車的傳感器數據&#xff0c;而某電商平臺的訂…

閉包與內存泄漏:深度解析與應對策略

在 JavaScript 編程中&#xff0c;閉包是一個強大且常用的特性&#xff0c;但如果使用不當&#xff0c;可能會引發內存泄漏問題&#xff0c;影響程序性能甚至導致頁面卡頓。本文將深入剖析閉包導致內存泄漏的原理&#xff0c;結合實例講解&#xff0c;并給出切實可行的避免方法…

open webui源碼分析12-Pipeline

Pipeline是 Open WebUI 的一項創新&#xff0c;它 為任何支持 OpenAI API 規范的 UI 客戶端帶來了模塊化、可定制的工作流 —— 甚至更多功能&#xff01;只需幾行代碼&#xff0c;你就能輕松擴展功能、集成自己的專有邏輯并創建動態工作流。 當你處理計算密集型任務&#xff0…

深入解析 Chromium Mojo IPC:跨進程通信原理與源碼實戰

在現代瀏覽器架構中&#xff0c;多進程設計已經成為標配。Chromium 瀏覽器作為典型的多進程瀏覽器&#xff0c;其瀏覽器進程&#xff08;Browser Process&#xff09;、渲染進程&#xff08;Renderer Process&#xff09;、GPU 進程、Utility 進程等之間的通信&#xff0c;依賴…

【自動化測試】測試分類概述-初步接觸自動化測試

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【Java】登神長階 史詩般的Java成神之路 測試分類 了解各種各樣的測試方法分類&#xff0c;不是為了墨守成規按照既定方法區測試&#xff0c;而是已了解思維為核心&#xff0c;并了解一些專業名詞 根…

【Python辦公】快速比較Excel文件中任意兩列數據的一致性

目錄 專欄導讀 項目背景 技術選型 核心技術棧 選型理由 功能特性 ?? 核心功能 ?? 輔助功能 架構設計 整體架構 設計模式 核心代碼解析 1. 類初始化和UI設置 2. 文件選擇和數據加載 3. 數據比較核心算法 4. 結果導出功能 界面設計詳解 布局結構 UI組件選擇 性能優化 1. 內存…

nginx的誕生背景、核心優勢、與 Apache 的對比

下面用“3 個 1 分鐘”幫你快速建立 Nginx 的整體印象&#xff1a; 1 分鐘了解它為何誕生&#xff0c;1 分鐘看懂它的 5 大核心優勢&#xff0c;再花 1 分鐘搞清和 Apache 的關鍵差異。誕生背景&#xff08;2002-2004&#xff09; ? 作者&#xff1a;俄羅斯系統工程師 Igor Sy…

算法題打卡力扣第169題:多數元素(easy)

文章目錄題目描述解法一&#xff1a;暴力解解法二 排序法解法三&#xff1a;Boyer-Moore 投票算法 (最優解)題目描述 解法一&#xff1a;暴力解 定義一個數組C用于存放nums數組中每個數出現的次數&#xff0c;然后再遍歷C&#xff0c;判斷C【i】是否大于? n/2 ?&#xff0c;…

A6.0:PCB的設計流程

第一步&#xff1a;導入網表第二步&#xff1a;結構導入和板框定義1.導入結構文件:加載DXF格式的機械結構圖(含板框、定位孔、限高區)&#xff0c;確保元件布局符合物理約束。2.固定器件預放置:將接插件、按鍵、散熱器等結構敏感元件鎖定到指定位置&#xff0c;避免后期調整沖突…

深度學習在金融訂單簿分析與短期市場預測中的應用

金融訂單簿記錄了市場上買賣雙方的委托訂單信息&#xff0c;包括價格、數量、訂單類型等關鍵要素。其數據具有以下特點&#xff1a; 高頻性&#xff1a;訂單在極短時間內不斷產生與變化&#xff0c;數據更新速度極快&#xff0c;每秒可能產生大量新訂單。序列性&#xff1a;訂單…

C++基礎算法——貪心算法

思想&#xff1a;總是做出在當前看來是最好的選擇 例題一、排隊打水問題 n個人&#xff0c;r個水龍頭&#xff0c;花費時間最少的安排&#xff1f;&#xff08;包含等待時間&#xff09; #include<iostream> #include <bits/stdc.h> using namespace std; int ma…

事務和鎖(進階)

事務和鎖&#xff08;進階&#xff09;一.回顧事務1.什么是事務2 為什么要使用事務3 怎么使用事務二.InnoDB和ACID模型三. 如何實現原子性四.如何實現持久性五.隔離性實現原理1.事務的隔離性2.事務的隔離級別3.鎖1&#xff09;鎖信息2&#xff09; 共享鎖和獨占鎖-Shared and E…

【Mentor Xpedition】預習一下

這個軟件不同于一般的PCB設計軟件&#xff0c;采用獨特的中心庫形式&#xff0c;相比cadence的SCH和PCB更緊湊&#xff0c;或者說本就是一家人&#xff0c;不像orcad和allegro強行捆在一起。 基本symbol給原理用&#xff0c;cell給PCB用。

通過代碼認識 CNN:用 PyTorch 實現卷積神經網絡識別手寫數字

目錄 一、從代碼看 CNN 的核心組件 二、準備工作&#xff1a;庫導入與數據加載 三、核心&#xff1a;用代碼實現 CNN 并理解各層作用 1.網絡層結構 2.重點理解&#xff1a;卷積層參數與輸出尺寸計算 四、訓練 CNN 五、結果分析 卷積神經網絡&#xff08;CNN&#xff09;…

基于SpringBoot和Thymeleaf開發的英語學習網站

角色&#xff1a; 管理員、用戶 技術&#xff1a; SpringBoot、Thymeleaf、MySQL、MyBatis、jQuery、Bootstrap 核心功能&#xff1a; 這是一個基于SpringBoot的英語學習平臺&#xff0c;旨在為用戶提供英語學習資料&#xff08;如書籍、聽力、單詞&#xff09;的管理和學習功能…

把 AI 塞進「智能跳繩」——基于 MEMS 傳感器的零樣本卡路里估算器

標簽&#xff1a;MEMS、卡路里估算、零樣本、智能跳繩、TinyML、RISC-V、低功耗、邊緣 AI ---- 1. 背景&#xff1a;為什么跳繩要「算卡路里」&#xff1f; 全球 1.5 億人把跳繩當日常運動&#xff0c;卻苦于&#xff1a; ? 機械計數器誤差大&#xff1b; ? 手機 App 需聯網…

礦用隨鉆測量現場應用中,最新的MEMS陀螺定向短節的優勢是什么?

在當代礦業開發向深部復雜地層進軍的過程中&#xff0c;隨鉆測量技術是控制鉆井定向打孔質量和提升長距離鉆探中靶精度的核心手段&#xff0c;煤礦井下定向鉆孔、瓦斯抽放孔、探放水孔等關鍵工程面臨著一系列特殊挑戰&#xff1a;強磁干擾、劇烈振動、空間受限等惡劣條件。最新…