JAVA從入門到精通一文搞定

博主介紹: 大家好,我是想成為Super的Yuperman,互聯網宇宙廠經驗,17年醫療健康行業的碼拉松奔跑者,曾擔任技術專家、架構師、研發總監負責和主導多個應用架構。
近期專注: DeepSeek應用,RPA應用研究,主流廠商產品使用,開源RPA 應用等
技術范圍: java體系,軟件架構,DDD,多年Golang、.Net、Oracle等經驗
業務范圍: 對傳統業務應用技術轉型,從數字醫院到區域醫療,從院內業務系統到互聯網醫院及健康服務,從公立醫院到私立醫院都有一些經歷及理解
*** 為大家分享一些思考與積累,歡迎持續關注公眾號:【火星求索】 ***

背景知識

Java 相關概念

  1. JavaSE (Java Standard Edition): 基礎版,用于開發桌面應用程序。
  2. JavaEE (Java Enterprise Edition): 企業版,用于開發企業級應用程序。
  3. JavaME (Java Micro Edition): 微型版,用于開發嵌入式系統和移動設備應用程序。

編譯與運行

  1. 編譯階段:

    • 源文件: .java 文件。
    • 字節碼文件: .class 文件。
    • 編譯工具: javac.exe,用于將 .java 文件編譯為 .class 文件。
      • 命令: javac 文件名.java
      • 編譯包: javac -d 編譯后存放路徑 java源文件路徑
  2. 運行階段:

    • 運行工具: java.exe,用于運行 .class 文件。
      • 命令: java 類名(不帶 .class 后綴)
    • JVM (Java Virtual Machine): Java 虛擬機,負責執行字節碼文件。

開發環境

  1. JDK (Java Development Kit): Java 開發工具包,包含編譯器、調試器等開發工具。
  2. JRE (Java Runtime Environment): Java 運行環境,包含 JVM 和運行 Java 程序所需的庫。
  3. JVM (Java Virtual Machine): Java 虛擬機,負責執行字節碼文件。

工具與格式

  1. native2ascii: 用于將 Unicode 字符轉換為 \u 表示的 ASCII 格式。
  2. UML (Unified Modeling Language): 面向對象設計圖,用于表示類、接口、繼承、實現等關系。
    • 空心箭頭: 指向父類(繼承)。
    • 空心虛線箭頭: 指向接口(實現)。
    • 實心實線箭頭: 表示關聯關系。

注釋

  1. 單行注釋: //
  2. 多行注釋: /* */
  3. 文檔注釋: /** */,用于生成幫助文檔。

類與方法結構

類體 {方法體 {java語句;}
}AI寫代碼java運行

總結

  • JavaSE 是基礎版,JavaEE 是企業版,JavaME 是微型版。
  • 編譯 使用 javac運行 使用 java
  • JDK 是開發工具包,JRE 是運行環境,JVM 是虛擬機。
  • UML 用于面向對象設計,注釋 用于代碼說明。
  • 類與方法 的基本結構如上所示。

Java SE API 和文檔

一、集成開發環境(IDEA)

以下是用戶提供的快捷鍵和組織方式的總結:


組織方式
  1. Project(工程): 最高層級,包含多個模塊。
  2. Module(模塊): 工程下的子模塊,包含多個包。
  3. Package(包): 模塊下的子包,用于組織類和資源。

字體設置
  • 路徑: File -> Settings -> Font
    用于調整編輯器的字體樣式和大小。

快捷鍵分類總結
導航與操作
  1. 展開/移動列表:

    • 左右箭頭: 展開或折疊列表。
    • 上下箭頭: 在列表中移動。
  2. 切換與定位:

    • Alt+左右箭頭: 切換 Java 程序。
    • Alt+上下箭頭: 在方法間快速移動。
    • Alt+標號: 打開標號窗口。
    • Ctrl+G: 定位到文件的某一行。
    • Ctrl+點擊: 切換源碼。
    • Ctrl+H: 查看實現類。
  3. 查找與搜索:

    • Ctrl+Shift+N: 查找文件。
    • Ctrl+N: 查找類文件。
    • Ctrl+F12: 在當前類中查找一個方法。

編輯與格式化
  1. 代碼編輯:

    • Ctrl+Y: 刪除一行。
    • Shift+F6: 重命名。
    • Alt+拖動: 一次編輯多行。
    • Ctrl+Alt+T: 將選中的代碼放在 TRY{}IF{}ELSE{} 中。
  2. 代碼提示與自動補全:

    • Ctrl+空格: 代碼提示。
    • Ctrl+P: 方法參數提示。
    • Ctrl+J: 自動代碼。
    • Ctrl+Alt+Space: 類名或接口名提示。
  3. 格式化與優化:

    • Ctrl+Alt+L: 格式化代碼。
    • Ctrl+Alt+I: 自動縮進。
    • Ctrl+Alt+O: 優化導入的類和包。

運行與糾錯
  1. 運行程序:

    • Ctrl+Shift+F10: 運行當前程序。
  2. 糾錯與提示:

    • Alt+回車: 糾錯提示。

窗口操作
  1. 全屏模式:
    • Ctrl+Shift+F12: 切換全屏模式。

總結
  • 組織方式: 工程 -> 模塊 -> 包,層級清晰,便于管理。
  • 快捷鍵:
    • 導航與查找:快速定位文件、類、方法。
    • 編輯與格式化:提高代碼編寫效率。
    • 運行與糾錯:快速運行程序并修復錯誤。
    • 窗口操作:優化開發環境布局。

二、JVM內存劃分

局部變量在方法體中聲明,運行階段內存在棧中分配

方法區內存:字節碼文件在加載 的時候將其放在方法區之中(最先有數據,調用方法時在棧內分配空間)

堆內存(heap):new對象(成員變量中的實例變量(一個對象一份)在java對象內部存儲),只能通過引用調用操作

棧(stack)內存:棧幀永遠指向棧頂元素,棧頂元素處于活躍狀態,先進后出,后進先出(存儲局部變量)

在這里插入圖片描述

內存區域與數據存儲
  1. 堆內存(Heap):

    • 存儲實例變量(對象屬性)。
    • 每個 JVM 實例只有一個堆內存,所有線程共享。
    • 垃圾回收器(GC)主要針對堆內存進行回收。
  2. 方法區(Method Area):

    • 存儲靜態變量(類變量)和類元數據(如類信息、常量池等)。
    • 每個 JVM 實例只有一個方法區,所有線程共享。
    • 方法區是最先有數據的內存區域,因為類加載時靜態變量和類信息會初始化。
  3. 棧內存(Stack):

    • 存儲局部變量和方法調用棧幀。
    • 每個線程有一個獨立的棧內存,線程私有。
    • 棧內存是使用最頻繁的內存區域,因為方法調用和局部變量的生命周期較短。

變量存儲位置
  1. 局部變量:

    • 存儲在棧內存中。
    • 生命周期與方法調用一致,方法結束時局部變量會被銷毀。
  2. 實例變量:

    • 存儲在堆內存中。
    • 生命周期與對象一致,對象被垃圾回收時實例變量會被銷毀。
  3. 靜態變量:

    • 存儲在方法區中。
    • 生命周期與類一致,類卸載時靜態變量會被銷毀。

垃圾回收器(GC)
  1. 主要目標:

    • 垃圾回收器主要針對堆內存進行回收,清理不再使用的對象。
    • 棧內存和方法區的垃圾回收機制與堆內存不同。
  2. 特點:

    • 堆內存是垃圾回收的主要區域,因為對象生命周期較長且占用內存較大。
    • 棧內存和方法區的垃圾回收效率較高,因為它們的生命周期較短且數據量相對較小。

三、關鍵字:

類與關鍵字
  1. public:

    • 表示公開的類,類名必須與文件名一致,且一個文件中只能有一個 public 類。
  2. class:

    • 用于定義一個類。
  3. static:

    • 表示靜態的,修飾的成員變量或方法屬于類級別,不依賴于對象。
    • 靜態變量在類加載時初始化,存儲在方法區內存中。
    • 靜態方法不能訪問實例變量或實例方法,需要通過對象訪問。
  4. break:

    • 用于跳出循環或 switch 語句。
  5. continue:

    • 用于跳過當前循環的剩余部分,直接進入下一次循環。
    • 語法:continue 循環名稱;循環名稱:
  6. this:

    • 表示當前對象的引用。
    • 用于區分局部變量和實例變量,或在構造方法中調用其他構造方法(this(實參))。
    • 不能用于靜態方法中。
  7. native:

    • 用于調用 JVM 本地程序。

輸入與輸出
  1. System.out.println():

    • 控制臺輸出,println 表示輸出并換行。
  2. 鍵盤輸入:

    • 創建鍵盤掃描器對象:java.util.Scanner s = new java.util.Scanner(System.in);
    • 字符串輸入:String user = s.next();
    • 整數輸入:int num = s.nextInt();

final 關鍵字
  1. 修飾類:

    • 類不能被繼承。
  2. 修飾方法:

    • 方法不能被重寫。
  3. 修飾變量:

    • 變量不能被修改。
    • 修飾的成員變量必須手動賦值。
    • 修飾的引用一旦指向一個對象,就不能指向其他對象,但所指向的內存可以修改。
  4. 常量:

    • 定義常量:public static final 類型 常量名 = 值;
    • 命名規則:全部大寫,用下劃線分隔。

super 關鍵字
  1. 作用:

    • 代表當前對象的父類型特征。
    • 用于訪問父類的屬性、方法或調用父類的構造方法。
  2. 語法:

    • 訪問父類屬性或方法:super.
    • 調用父類構造方法:super()
  3. 規則:

    • 不能用于靜態方法中。
    • 如果父類和子類有同名屬性,訪問父類屬性時不能省略 super
    • 構造方法的第一行如果沒有 this()super(),默認會調用 super()

static 關鍵字
  1. 靜態變量:

    • 屬于類級別,不依賴于對象,類加載時初始化。
  2. 靜態方法:

    • 類級別的方法,不能訪問實例變量或實例方法。
  3. 靜態代碼塊:

    • 在類加載時執行,只執行一次。
    • 語法:static {}
  4. 實例代碼塊:

    • 在構造方法執行之前執行,用于對象初始化。

包與導入
  1. package:

    • 用于管理類,命名規則:公司域名倒序.項目名.模塊名.功能名。
    • 語法:package 包名;
  2. import:

    • 用于導入包中的類。
    • 語法:import 包名.類名;import 包名.*;
    • java.lang.* 是核心語言包,無需導入。
  3. 快捷鍵:

    • Ctrl+Shift+O:自動導入。

訪問控制權限修飾符
  1. private:

    • 私有訪問權限,只能在本類中訪問。
  2. default:

    • 默認訪問權限,可以被本包中的其他類訪問。
  3. protected:

    • 受保護的訪問權限,可以被本包及不同包的子類訪問。
  4. public:

    • 公共訪問權限,可以在任何地方訪問。
  5. 類的修飾符:

    • 類只能使用 public 或默認修飾符(缺省),內部類除外。

總結
  • 類與關鍵字publicclassstaticthissuper 等關鍵字的作用與用法。
  • 輸入與輸出:控制臺輸出與鍵盤輸入的基本操作。
  • final:用于修飾類、方法、變量,表示不可修改。
  • static:修飾類級別的成員,與對象無關。
  • 包與導入packageimport 的使用及命名規則。
  • 訪問控制權限privatedefaultprotectedpublic 的訪問范圍。

四、Java基礎

以下是用戶提供的內容的總結:


標識符
  1. 定義:

    • 用戶有權命名的單詞,包括類名、方法名、常量名、變量名、接口名等。
  2. 命名規則:

    • 類名、接口名: 首字母大寫,后面每個單詞首字母大寫(大駝峰命名法)。
    • 方法名、變量名: 首字母小寫,后面每個單詞首字母大寫(小駝峰命名法)。
    • 常量名: 全部大寫,單詞間用下劃線分隔。

字面值
  • 定義: 數據本身,如數字、字符串等,通常以紫色顯示。

變量
  1. 局部變量:

    • 定義在方法體內,沒有默認值,必須手動初始化。
    • 生命周期與方法調用一致。
  2. 成員變量:

    • 定義在類體內,有默認值(數值類型為 0,布爾類型為 false,引用類型為 null)。
    • 分為實例變量和靜態變量。
  3. 實例變量:

    • 不帶 static 關鍵字,屬于對象級別。
    • 必須通過對象引用訪問(引用.變量名)。
    • 存儲在堆內存中。
  4. 靜態變量:

    • static 關鍵字,屬于類級別。
    • 在類加載時初始化,存儲在方法區內存中。
    • 通過類名訪問(類名.變量名)。

引用
  • 定義: 是一個變量,可以是實例變量或局部變量。
    • 實例變量: 類名 引用 = new 類名();
    • 局部變量: 引用 變量名 = new 引用();

數據類型
  1. 基本數據類型:

    • 整數型: byte(1 字節)、short(2 字節)、int(4 字節)、long(8 字節,后綴 L)。
    • 浮點型: float(4 字節)、double(8 字節)。
    • 布爾型: boolean(1 字節)。
    • 字符型: char(2 字節)。
  2. 引用數據類型:

    • 字符串: String,不可變,存儲在方法區字符串池中。
  3. 比較:

    • 基本數據類型使用 == 判斷相等。
    • 引用數據類型(包括 String)使用 equals 判斷相等。

字符編碼
  • 發展順序: ASCII < ISO-8859-1 < GB2312 < GBK < GB18030 < Big5 < Unicode(統一全球編碼)。

位運算符
  1. 邏輯異或(^): 兩邊不一樣為真。
  2. 短路與(&&): 左邊為假時直接返回假。
  3. 按位與(&): 將操作數轉換為二進制后按位與。
  4. 短路或(||): 左邊為真時直接返回真。
  5. 左移(<<): 二進制數據左移,相當于乘以 2 的 N 次方。
  6. 右移:
    • 帶符號右移(>>): 正數用 0 填充,負數用 1 填充。
    • 無符號右移(>>>): 無論正負都用 0 填充。
  7. 按位取反(~): 將二進制每一位取反,結果為 -(n+1)

方法(函數)
  1. 定義:

    [修飾符列表] 返回值類型 方法名(形參列表) {方法體;return; // return 后不能跟語句
    }AI寫代碼java運行
    
  2. 調用: 類名.方法名(實參列表);

  3. 實例方法: 不帶 static,需要對象參與。

  4. 靜態方法: 帶 static,與對象無關。


方法重載(Overload)
  • 定義: 在同一類中,方法名相同但參數列表不同。
  • 特點: 與返回值類型和修飾符列表無關。

方法遞歸
  • 定義: 方法調用自身,每次遞歸都會分配新的內存空間(壓棧)。

在這里插入圖片描述

  • 示例:

    public static int sum(int n) {if (n == 1) {return 1;}return n + sum(n - 1);
    }AI寫代碼java運行
    

方法覆蓋(Override)
  1. 定義: 發生在繼承關系中,子類重寫父類的方法。
  2. 規則:
    • 方法名、返回值類型、形參列表必須與父類一致。
    • 訪問權限不能比父類更低,拋出異常不能更多。
  3. 限制:
    • 私有方法、構造方法不能覆蓋。
    • 靜態方法不存在覆蓋。

總結
  • 標識符: 命名規則與用途。
  • 變量: 局部變量、實例變量、靜態變量的定義與存儲位置。
  • 數據類型: 基本數據類型與引用數據類型的區別。
  • 位運算符: 各種位運算符的作用與用法。
  • 方法: 定義、調用、重載、遞歸與覆蓋的規則與特點。

五、Java 控制流與 Lambda 表達式

1. 控制流語句
  • If-Else 語句

    if (條件) {// 語句
    } else if (表達式) {// 語句
    } else {// 語句
    }AI寫代碼java運行
    
  • Switch 語句

    switch (關鍵詞) {case 關鍵詞:// java語句break;default:// 默認語句
    }AI寫代碼java運行
    
  • For 循環

    for (初始表達式; 布爾表達式; 更新循環體) {// 循環體
    }AI寫代碼java運行
    
  • 增強 For 循環(For Each)

    for (元素類型 變量名 : 數組或集合) {System.out.println(變量名);
    }AI寫代碼java運行
    
  • While 循環

    while (表達式) {// 循環體
    }AI寫代碼java運行
    
  • Do-While 循環

    do {// 循環體
    } while (布爾表達式);AI寫代碼java運行
    
2. Java 標簽
  • 標簽用于控制嵌套循環的跳轉和中斷。
  • 語法label:
  • 用法
    • continue label;:跳過當前循環,繼續執行標簽處的循環。
    • break label;:結束標簽處的循環,執行循環后的代碼。
3. Lambda 表達式
  • 實現 Runnable

    // Java 8 之前
    new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Before Java8, too much code for too little to do");}
    }).start();// Java 8 方式
    new Thread(() -> System.out.println("In Java8, Lambda expression rocks !!")).start();AI寫代碼java運行
    
  • 事件處理

    // Java 8 之前
    JButton show = new JButton("Show");
    show.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("Event handling without lambda expression is boring");}
    });// Java 8 方式
    show.addActionListener((e) -> {System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
    });AI寫代碼java運行
    
  • 列表迭代

    // Java 8 之前
    List<String> features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
    for (String feature : features) {System.out.println(feature);
    }// Java 8 之后
    features.forEach(n -> System.out.println(n));
    // 使用方法引用
    features.forEach(System.out::println);AI寫代碼java運行
    
  • Map 和 Reduce

    // 不使用 lambda 表達式
    List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    for (Integer cost : costBeforeTax) {double price = cost + .12 * cost;System.out.println(price);
    }// 使用 lambda 表達式
    costBeforeTax.stream().map((cost) -> cost + .12 * cost).forEach(System.out::println);// 使用 reduce 計算總和
    double bill = costBeforeTax.stream().map((cost) -> cost + .12 * cost).reduce((sum, cost) -> sum + cost).get();
    System.out.println("Total : " + bill);AI寫代碼java運行
    
  • 對列表的每個元素應用函數

    List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.", "Canada");
    String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
    System.out.println(G7Countries);AI寫代碼java運行
    
  • 計算集合元素的最大值、最小值、總和以及平均值

    List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
    IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
    System.out.println("Highest prime number in List : " + stats.getMax());
    System.out.println("Lowest prime number in List : " + stats.getMin());
    System.out.println("Sum of all prime numbers : " + stats.getSum());
    System.out.println("Average of all prime numbers : " + stats.getAverage());AI寫代碼java運行
    
總結
  • 控制流語句:用于控制程序的執行流程,包括條件判斷、循環等。
  • Java 標簽:用于控制嵌套循環的跳轉和中斷。
  • Lambda 表達式:簡化了匿名類的使用,使代碼更簡潔,特別是在實現函數式接口(如 RunnableActionListener)時非常有用。
  • Stream API:提供了強大的集合操作功能,如 mapreduceforEach 等,使得對集合的處理更加高效和簡潔。

六、面向對象

面向過程與面向對象的對比
  1. 面向過程

    • 因果關系:關注問題的具體步驟和流程。
    • 具體過程:強調如何一步步解決問題。
    • 耦合度高:各個模塊之間依賴性強,修改一個模塊可能會影響其他模塊。
    • 軟件拓展性差:由于耦合度高,系統的擴展和維護較為困難。
  2. 面向對象

    • 分類對象:將問題分解為多個對象,每個對象負責特定的功能。
    • 關系層度低:對象之間的依賴關系較弱,耦合度低。
    • 關注對象功能:關注對象能完成哪些功能,而不是具體的實現步驟。
    • 三大特征
      • 封裝性:將復雜的事務封裝起來,只保留簡單的操作入口。封裝后形成獨立的對象,提高了代碼的復用性、適應性和安全性。
      • 繼承性:實現代碼復用,最重要的是支持多態和方法覆蓋。
      • 多態性:父類型的引用可以指向子類型對象,降低程序耦合度,提高擴展力。
面向對象的分析與設計
  • 面向對象的分析(OOA):分析問題域,識別對象及其關系。
  • 面向對象的設計(OOD):設計對象的結構和行為,定義類及其關系。
  • 面向對象的編程(OOP):使用編程語言實現設計,創建對象并實現其功能。
類與對象
  • :高度抽象的對象的集合,是一個模板。
    • 靜態代碼塊:類加載時執行。
    • 實例代碼塊:實例化時執行。
    • 靜態變量:類級別的變量。
    • 實例變量:對象級別的變量,存儲在堆內存中。
    • 構造方法:創建對象時調用,用于初始化實例變量。
    • 靜態方法:類級別的方法。
    • 實例方法:對象級別的方法。
    • 成員變量:對象的屬性,描述對象的狀態。
    • 成員方法:對象的行為,描述對象的動作。
  • 對象:類的具體實例。
    • 創建對象類名 對象名稱 = new 類名();
    • 使用對象對象名稱.屬性名對象名稱.方法名()
    • 修改對象引用.變量名 = 值
    • 引用與對象:引用保存了對象的地址,指向堆內存中的對象。多個引用可以指向同一個對象,但一個引用只能指向一個對象。
User u=new User();
Address a=new Address();
u.addr=a;
Print(u.addr.city);
A.city=”天津”;
Print(u.addr.city);                                      AI寫代碼java運行

在這里插入圖片描述

封裝
  • 私有化屬性:使用private關鍵字將屬性私有化。
  • 提供操作入口:通過gettersetter方法提供對屬性的訪問和修改。
    • 讀取屬性public 數據類型 get屬性名() { return 屬性; }
    • 修改屬性public void set屬性名(數據類型 屬性) { this.屬性 = 屬性; }
  • 業務邏輯控制:在setter方法中添加業務邏輯進行安全控制。
構造方法
  • 作用:創建對象并初始化實例變量。
  • 語法修飾符 構造方法名(形參) { 構造方法體; this.實例變量 = 形參; }
  • 特點:沒有返回值類型,方法名與類名一致,不能使用return返回值,但可以使用return結束方法。
  • 調用new 構造方法名(實參)
  • 缺省構造器:如果沒有定義構造方法,編譯器會自動生成一個無參的缺省構造器。
繼承
  • 語法[修飾符列表] class 子類名 extends 父類名 { 類體 = 屬性 + 方法 }
  • 單繼承:Java中類只能繼承一個父類。
  • 繼承關系
    • 父類:也稱為基類、超類、superclass
    • 子類:也稱為派生類、subclass
  • 不可繼承:私有的屬性和方法、構造方法。
  • 間接繼承:通過繼承鏈,子類可以間接繼承父類的父類。
  • 默認繼承:如果沒有顯式繼承任何類,默認繼承java.lang.Object類。
  • super關鍵字:用于調用父類的屬性、方法和構造方法。
多態
  • 向上轉型(Upcasting):子類轉換為父類型,自動類型轉換。
    • 語法父類 引用 = new 子類();
    • 特點:編譯通過,運行沒有問題。
  • 向下轉型(Downcasting):父類轉換為子類,強制類型轉換。
    • 語法子類 引用 = (子類) 父類引用;
    • 特點:存在隱患,可能導致ClassCastException異常。
  • 動態綁定:父類型引用指向子類型對象,調用方法時實際執行的是子類的方法。
  • instanceof運算符:用于在強制轉換前檢查對象的類型,避免ClassCastException異常。
    • 語法引用 instanceof 數據類型名
    • 返回值:布爾類型,true表示引用指向的對象是后面的數據類型,false表示不是。

以下是關于 抽象類接口 的總結:


抽象類
  1. 定義:

    • 使用 abstract 關鍵字修飾的類,是類的進一步抽象。
    • 屬于引用數據類型。
  2. 語法:

    [修飾符列表] abstract class 類名 {}AI寫代碼java運行
    
  3. 特點:

    • 不能使用 privatefinal 修飾。
    • 抽象類可以包含抽象方法和非抽象方法。
    • 抽象類的子類可以是抽象類或非抽象類。
    • 不能實例化(不能創建對象),但可以有構造方法,供子類使用。
  4. 抽象方法:

    • 使用 abstract 關鍵字修飾,無方法體。
    • 語法:[修飾符列表] abstract 返回值類型 方法名();
    • 包含抽象方法的類一定是抽象類。
  5. 規則:

    • 抽象類不一定有抽象方法,但抽象方法必須出現在抽象類中。
    • 非抽象類繼承抽象類時,必須實現所有抽象方法。

接口
  1. 定義:

    • 使用 interface 關鍵字定義,是完全抽象的(特殊的抽象類)。
    • 屬于引用數據類型。
  2. 語法:

    [修飾符列表] interface 接口名 {}AI寫代碼java運行
    
  3. 特點:

    • 接口中只能包含常量和抽象方法(默認 public static finalpublic abstract,修飾符可省略)。
    • 支持多繼承,一個接口可以繼承多個接口。
    • 接口不能繼承抽象類。
  4. 方法類型:

    • 抽象方法: abstract 修飾(可省略)。
    • 默認方法: default 修飾,提供默認實現。
    • 靜態方法: static 修飾,通過接口名調用。
  5. 實現:

    • 類通過 implements 關鍵字實現接口。
    • 非抽象類實現接口時,必須重寫所有抽象方法。
    • 一個類可以實現多個接口。
  6. 多態:

    • 接口支持多態:父類型引用指向子類對象
    • 示例:接口名 引用 = new 實現類();
  7. 作用:

    • 解耦合:調用者面向接口調用,實現者面向接口編寫實現。
    • 擴展性強:接口+多態可以降低程序耦合度。

抽象類與接口的區別
特性抽象類接口
抽象程度半抽象(可以包含具體方法)完全抽象(只能包含抽象方法)
構造方法有構造方法,供子類使用無構造方法
繼承單繼承(一個類只能繼承一個抽象類)支持多繼承(一個類可以實現多個接口)
內容可以包含抽象方法和非抽象方法只能包含常量和抽象方法
用途抽象行為和數據主要抽象行為
實例化不能實例化不能實例化

開發中的選擇
  1. 抽象類:

    • 當多個類有共同的屬性和行為,且需要部分具體實現時使用。
    • 適合定義“是什么”(is-a 關系)。
  2. 接口:

    • 當需要定義一組行為規范,且不關心具體實現時使用。
    • 適合定義“能做什么”(like-a 關系)。

示例
  1. 抽象類:

    abstract class Animal {abstract void sound();void sleep() {System.out.println("Sleeping...");}
    }AI寫代碼java運行
    
  2. 接口:

    interface Flyable {void fly();
    }AI寫代碼java運行
    
  3. 實現與繼承:

    class Bird extends Animal implements Flyable {@Overridevoid sound() {System.out.println("Chirp...");}@Overridepublic void fly() {System.out.println("Flying...");}
    }AI寫代碼java運行
    

總結
  • 面向對象編程通過封裝、繼承和多態三大特征,提高了代碼的復用性、擴展性和維護性。

  • 類與對象是面向對象編程的基礎,類是對對象的抽象,對象是類的實例。

  • 封裝通過私有化屬性和提供操作入口,增強了代碼的安全性和可控性。

  • 繼承實現了代碼的復用,并支持多態和方法覆蓋。

  • 多態通過向上轉型和向下轉型,降低了程序的耦合度,提高了擴展力。

  • 面向抽象編程,而不是面向具體,可以進一步降低耦合度,提高系統的靈活性和可擴展性。

  • 抽象類 用于定義類的共有特征,支持部分具體實現。

  • 接口 用于定義行為規范,支持多繼承和解耦合。

  • 在實際開發中,根據需求選擇抽象類或接口,合理使用可以提高代碼的擴展性和可維護性。

七、類庫

源碼、字節碼與幫助文檔
  1. 源碼

    • 理解程序:源碼是程序員編寫的原始代碼,用于理解程序的邏輯和功能。
  2. 字節碼

    • 程序開發使用:字節碼是源碼編譯后的中間代碼,由JVM執行。它是跨平臺的,可以在任何支持JVM的系統上運行。
  3. 幫助文檔

    • 對開發提供幫助:幫助文檔是開發者的參考指南,通常通過javadoc生成。
    • 注意使用版本同一:確保使用的幫助文檔與代碼版本一致,避免因版本差異導致的錯誤。

Object類(根類)

Object是Java中所有類的根類,提供了一些核心方法:

  1. protected Object clone()

    • 負責對象克隆,返回對象的副本。
  2. boolean equals(Object obj)

    • 判斷兩個對象是否相等。默認比較引用地址,通常需要重寫以比較對象內容。
  3. int hashCode()

    • 返回對象的哈希代碼值,用于哈希表等數據結構。
  4. String toString()

    • 返回對象的字符串表示形式。默認返回類名@哈希值,通常需要重寫以提供更有意義的信息。
  5. protected void finalize() throws Throwable

    • 垃圾回收器負責調用,用于對象銷毀前的清理工作。
  6. System.gc()

    • 建議啟動垃圾回收器,但不保證立即執行。

System類

System類提供了一些系統級別的操作:

  1. System.gc()

    • 建議啟動垃圾回收器。
  2. System.out

    • 靜態變量,用于控制臺輸出。
  3. System.out.print()

    • 輸出打印不換行。
  4. System.out.println()

    • 換行輸出。
  5. System.currentTimeMillis()

    • 獲取自1970年1月1日00:00:00到當前系統時間的總毫秒數。
  6. System.exit(0)

    • 退出JVM。

Arrays類

Arrays是數組工具類,提供了一些常用方法:

  1. Arrays.sort(arr)

    • 對數組進行排序。
  2. Arrays.binarySearch(arr, key)

    • 使用二分法查找元素,不存在時返回-1。

String類

String類用于操作字符串,提供了豐富的構造方法和方法:

  1. 構造方法

    • String(byte[] byte):將字節數組轉換為字符串。
    • String(char[] char):將字符數組轉換為字符串。
    • String(String string):復制字符串。
  2. 常用方法

    • char charAt(int index):返回指定索引的字符。
    • int compareTo(String string):字典比較大小。
    • boolean contains(String string):判斷是否包含指定字符串。
    • boolean endsWith(String string):判斷是否以指定字符串結尾。
    • boolean startsWith(String prefix):判斷是否以指定前綴開頭。
    • boolean equals(Object anObject):比較字符串內容。
    • boolean equalsIgnoreCase(String anotherString):忽略大小寫比較。
    • byte[] getBytes():將字符串轉換為字節數組。
    • int indexOf(String str):返回子字符串第一次出現的索引。
    • int lastIndexOf(String str):返回子字符串最后一次出現的索引。
    • boolean isEmpty():判斷字符串是否為空。
    • String replace(CharSequence target, CharSequence replacement):替換字符串。
    • String substring(int beginIndex):截取字符串。
    • char[] toCharArray():將字符串轉換為字符數組。
    • String toLowerCase():將字符串轉換為小寫。
    • String toUpperCase():將字符串轉換為大寫。
    • String[] split(String regex):按正則表達式拆分字符串。
    • String trim():去除前后空白。
    • static String valueOf():將其他類型轉換為字符串。

StringBuffer與StringBuilder
  1. StringBuffer

    • 線程安全,適用于多線程環境。
    • 常用方法:append()reverse()
  2. StringBuilder

    • 非線程安全,性能優于StringBuffer

包裝類

包裝類用于將基本數據類型轉換為對象:

  1. 常用包裝類
    • IntegerCharacter等。
  2. 常用方法
    • int intValue():拆箱,將包裝類轉換為基本類型。
    • static int parseInt(String s):將字符串轉換為整數。

在這里插入圖片描述


日期相關類
  1. java.util.Date

    • 表示日期和時間。
  2. SimpleDateFormat

    • 用于格式化日期。
    • 常用方法:format()parse()

數字相關類
  1. DecimalFormat

    • 用于格式化數字。
  2. BigDecimal

    • 用于高精度計算,適用于財務數據。
  3. Random

    • 用于生成隨機數。

枚舉(Enum)

枚舉是一種特殊的類,用于定義一組常量:

enum Season {SPRING, SUMMER, AUTUMN, WINTER
}AI寫代碼java運行

內部類
  1. 成員內部類

    • 定義在類中,可以訪問外部類的所有成員。
  2. 局部內部類

    • 定義在方法中,只能在該方法內訪問。
  3. 靜態內部類

    • 使用static修飾,只能訪問外部類的靜態成員。
  4. 匿名內部類

    • 沒有名稱的內部類,通常用于實現接口或抽象類。

總結
  • 源碼是理解程序的基礎,字節碼是程序運行的關鍵,幫助文檔是開發的指南。
  • Object是Java的根類,提供了對象的基本操作。
  • System類提供了系統級別的操作,如垃圾回收、時間獲取等。
  • String類用于操作字符串,提供了豐富的構造方法和方法。
  • StringBufferStringBuilder用于字符串的拼接和修改,前者線程安全,后者性能更優。
  • 包裝類用于將基本數據類型轉換為對象。
  • 日期相關類用于處理日期和時間。
  • 內部類提供了更靈活的代碼組織方式。

八、數組

一維數組
  1. 定義:

    • 數組是引用數據類型,存儲在堆內存中。
    • 可以存儲各種數據類型,但不能直接存儲對象,存儲的是對象的引用(內存地址)。
  2. 特點:

    • 數組元素類型統一,最后一個下標為 length - 1
    • 帶有 length 屬性,用于獲取數組長度。
  3. 優點:

    • 查詢、查找、檢索某個下標元素效率極高(內存連續,類型相同)。
  4. 缺點:

    • 隨機增刪元素效率較低。
    • 不能存儲大數據量。
  5. 定義與初始化:

    • 靜態初始化:

      數據類型[] 數組名 = {元素1, 元素2, ...};AI寫代碼java運行
      
    • 動態初始化:

      數據類型[] 數組名 = new 數據類型[長度];AI寫代碼java運行
      
  6. 賦值:

    數組名[下標] =;AI寫代碼java運行
    
  7. 遍歷:

    • 使用 for 循環或增強 for 循環:

      for (int i = 0; i < 數組名.length; i++) {System.out.println(數組名[i]);
      }AI寫代碼java運行
      
  8. 方法參數:

    • 數組可以作為方法的參數:

      void 方法名(數據類型[] 數組名) {}AI寫代碼java運行
      
  9. main 方法的數組參數:

    • main 方法的參數是一個字符串數組,用于接收命令行參數:

      public static void main(String[] args) {}AI寫代碼java運行
      
  10. 存儲對象:

    • 數組可以存儲對象的引用:

      類名[] 數組名 = new 類名[長度];
      數組名[0] = new 類名();AI寫代碼java運行
      
  11. 數組擴容:

    • 新建一個大數組,然后將原數組拷貝過去:

      int[] newArray = new int[原數組.length * 2];
      System.arraycopy(原數組, 0, newArray, 0, 原數組.length);AI寫代碼java運行
      
  12. 數組拷貝:

    • 使用 System.arraycopy 方法:

      System.arraycopy(原數組, 原起點, 目標數組, 目標下標, 長度);AI寫代碼java運行
      

二維數組
  1. 定義:

    • 二維數組是數組的數組,可以看作是一個表格。
  2. 語法:

    數據類型[][] 數組名 = new 數據類型[行數][列數];AI寫代碼java運行
    
  3. 初始化:

    • 靜態初始化:

      數據類型[][] 數組名 = {{元素1, 元素2}, {元素3, 元素4}};AI寫代碼java運行
      
    • 動態初始化:

      數據類型[][] 數組名 = new 數據類型[行數][列數];AI寫代碼java運行
      
  4. 遍歷:

    • 使用嵌套 for 循環:

      for (int i = 0; i < 數組名.length; i++) {for (int j = 0; j < 數組名[i].length; j++) {System.out.println(數組名[i][j]);}
      }AI寫代碼java運行
      

總結
  1. 一維數組:

    • 適用于存儲一組相同類型的數據。
    • 查詢效率高,增刪效率低。
    • 可以通過 length 屬性獲取長度。
    • 支持靜態初始化和動態初始化。
  2. 二維數組:

    • 適用于存儲表格型數據。
    • 可以看作是一維數組的數組。
    • 支持靜態初始化和動態初始化。
  3. 數組的優缺點:

    • 優點:查詢效率高,內存連續。
    • 缺點:增刪效率低,不能存儲大數據量。
  4. 數組的應用場景:

    • 存儲一組固定長度的數據。
    • 存儲對象引用。
    • 存儲表格型數據(二維數組)。

示例
  1. 一維數組:

    int[] arr = {1, 2, 3, 4, 5};
    for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);
    }AI寫代碼java運行
    
  2. 二維數組:

    int[][] arr = {{1, 2}, {3, 4}};
    for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr[i].length; j++) {System.out.println(arr[i][j]);}
    }AI寫代碼java運行
    
  3. 數組存儲對象:

    Animal[] animals = new Animal[2];
    animals[0] = new Cat();
    animals[1] = new Dog();AI寫代碼java運行
    
  4. 數組擴容:

    int[] src = {1, 2, 3};
    int[] dest = new int[src.length * 2];
    System.arraycopy(src, 0, dest, 0, src.length);AI寫代碼java運行
    

通過合理使用數組,可以高效地存儲和操作數據,但需要注意其增刪效率較低的缺點。

九、算法

以下是常見 排序算法查找算法 的思想總結,并附帶 Java 實例:


排序算法
  1. 冒泡排序(Bubble Sort):

    • 思想:重復遍歷數組,每次比較相鄰元素,如果順序錯誤則交換,直到沒有需要交換的元素。

    • 時間復雜度:O(n2)。

    • Java 實現:

      public static void bubbleSort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
      }AI寫代碼java運行
      
  2. 選擇排序(Selection Sort):

    • 思想:每次從未排序部分選擇最小元素,放到已排序部分的末尾。

    • 時間復雜度:O(n2)。

    • Java 實現:

      public static void selectionSort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {int minIndex = i;for (int j = i + 1; j < arr.length; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}
      }AI寫代碼java運行
      
  3. 插入排序(Insertion Sort):

    • 思想:將未排序部分的元素逐個插入到已排序部分的正確位置。

    • 時間復雜度:O(n2)。

    • Java 實現:

      public static void insertionSort(int[] arr) {for (int i = 1; i < arr.length; i++) {int key = arr[i];int j = i - 1;while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
      }AI寫代碼java運行
      
  4. 快速排序(Quick Sort):

    • 思想:選擇一個基準元素,將數組分為兩部分,左邊小于基準,右邊大于基準,遞歸排序。

    • 時間復雜度:O(n log n)。

    • Java 實現:

      public static void quickSort(int[] arr, int low, int high) {if (low < high) {int pivot = partition(arr, low, high);quickSort(arr, low, pivot - 1);quickSort(arr, pivot + 1, high);}
      }private static int partition(int[] arr, int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; j++) {if (arr[j] < pivot) {i++;int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}int temp = arr[i + 1];arr[i + 1] = arr[high];arr[high] = temp;return i + 1;
      }AI寫代碼java運行
      
  5. 歸并排序(Merge Sort):

    • 思想:將數組分成兩半,分別排序,然后合并。

    • 時間復雜度:O(n log n)。

    • Java 實現:

      public static void mergeSort(int[] arr, int left, int right) {if (left < right) {int mid = (left + right) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}
      }private static void merge(int[] arr, int left, int mid, int right) {int[] temp = new int[right - left + 1];int i = left, j = mid + 1, k = 0;while (i <= mid && j <= right) {if (arr[i] <= arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}while (i <= mid) {temp[k++] = arr[i++];}while (j <= right) {temp[k++] = arr[j++];}for (int p = 0; p < temp.length; p++) {arr[left + p] = temp[p];}
      }AI寫代碼java運行
      

查找算法
  1. 線性查找(Linear Search):

    • 思想:從頭到尾遍歷數組,逐個比較,找到目標元素。

    • 時間復雜度:O(n)。

    • Java 實現:

      public static int linearSearch(int[] arr, int target) {for (int i = 0; i < arr.length; i++) {if (arr[i] == target) {return i;}}return -1;
      }AI寫代碼java運行
      
  2. 二分查找(Binary Search):

    • 思想:在有序數組中,每次取中間元素與目標比較,縮小查找范圍。

    • 時間復雜度:O(log n)。

    • Java 實現:

      public static int binarySearch(int[] arr, int target) {int left = 0, right = arr.length - 1;while (left <= right) {int mid = (left + right) / 2;if (arr[mid] == target) {return mid;} else if (arr[mid] < target) {left = mid + 1;} else {right = mid - 1;}}return -1;
      }AI寫代碼java運行
      

總結
  1. 排序算法:

    • 冒泡排序:簡單但效率低,適合小規模數據。
    • 選擇排序:每次選擇最小元素,適合小規模數據。
    • 插入排序:適合部分有序的數據。
    • 快速排序:高效,適合大規模數據。
    • 歸并排序:穩定且高效,適合大規模數據。
  2. 查找算法:

    • 線性查找:適合無序數據。
    • 二分查找:適合有序數據,效率高。
  3. 選擇依據:

    • 數據規模、是否有序、穩定性要求等。

示例
public class Main {public static void main(String[] args) {int[] arr = {5, 3, 8, 4, 2};bubbleSort(arr);System.out.println("冒泡排序結果: " + Arrays.toString(arr));int[] arr2 = {5, 3, 8, 4, 2};quickSort(arr2, 0, arr2.length - 1);System.out.println("快速排序結果: " + Arrays.toString(arr2));int target = 4;int index = binarySearch(arr2, target);System.out.println("二分查找結果: " + (index != -1 ? "找到,下標為 " + index : "未找到"));}
}AI寫代碼java運行

輸出:

冒泡排序結果: [2, 3, 4, 5, 8]
快速排序結果: [2, 3, 4, 5, 8]
二分查找結果: 找到,下標為 2AI寫代碼

通過合理選擇排序和查找算法,可以高效地處理數據。

十、異常

1. 異常的基本概念
  • 異常在 Java 中以類的方式存在,每個異常類都可以創建異常對象。
  • 方法覆蓋規則:子類重寫父類方法時,不能拋出比父類方法更高的異常(運行時異常 RuntimeException 除外)。
  • 異常的分類
    • java.lang.Throwable:異常的父類,有兩個子類:
      • Error:錯誤,通常是系統級錯誤(如 OutOfMemoryError),不可處理,只能退出程序。
      • Exception:異常,所有異常都是在運行階段發生的。
        • Exception 的直接子類:編譯時異常(受檢異常 CheckedException),需要在編寫程序時預處理。
        • RuntimeException:運行時異常,通常由程序邏輯錯誤引起,不需要顯式處理。

2. 常見運行時異常
  • NullPointerException:空指針異常,嘗試訪問 null 對象的成員。
  • ArrayIndexOutOfBoundsException:數組下標越界異常。
  • ClassCastException:類型轉換異常,嘗試將對象強制轉換為不兼容的類型。
  • NumberFormatException:數字轉換異常,嘗試將非數字字符串轉換為數字。

3. 異常處理方式
  1. throws 關鍵字

    • 在方法聲明位置使用,將異常拋給調用者處理。

    • 示例:

      public void readFile() throws IOException {// 可能拋出 IOException 的代碼
      }AI寫代碼java運行
      
  2. try-catch-finally 語句

    • 捕獲并處理異常。

    • 示例:

      try {// 可能拋出異常的代碼
      } catch (NullPointerException e) {System.out.println("空指針異常: " + e.getMessage());
      } catch (ArrayIndexOutOfBoundsException e) {System.out.println("數組下標越界: " + e.getMessage());
      } finally {// 無論是否發生異常,都會執行的代碼System.out.println("finally 塊執行");
      }AI寫代碼java運行
      

4. 常用異常方法
  • getMessage():獲取異常的簡單描述信息(通常是構造方法的參數)。
  • printStackTrace():打印異常的堆棧追蹤信息(異步線程中常用)。

5. 自定義異常
  • 步驟

    1. 編寫一個類繼承 Exception(受檢異常)或 RuntimeException(運行時異常)。
    2. 提供兩個構造方法:一個無參,一個有參。
    3. 使用 throw 手動拋出異常。
  • 示例

    // 自定義異常類
    public class MyException extends Exception {public MyException() {super();}public MyException(String message) {super(message);}
    }// 使用自定義異常
    public class Test {public static void main(String[] args) {try {throw new MyException("自定義異常發生");} catch (MyException e) {System.out.println(e.getMessage());}}
    }AI寫代碼java運行
    

6. 異常處理的最佳實踐
  • 明確異常類型:捕獲具體異常,而不是直接捕獲 Exception
  • 合理使用 finally:用于釋放資源(如關閉文件、數據庫連接等)。
  • 避免空指針異常:在使用對象前進行 null 檢查。
  • 日志記錄:使用日志框架(如 Log4jSLF4J)記錄異常信息,便于排查問題。

總結
  • 異常分類ErrorException,其中 Exception 分為編譯時異常和運行時異常。
  • 處理方式throws 拋給調用者,try-catch-finally 捕獲并處理。
  • 自定義異常:繼承 ExceptionRuntimeException,提供構造方法,使用 throw 拋出。
  • 最佳實踐:明確異常類型,合理使用 finally,避免空指針異常,記錄日志。

十一、I/O

I/O(輸入/輸出)概述

I/O(Input/Output)是指應用程序與外部設備(如磁盤、網絡、鍵盤、顯示器等)之間的數據交互。Java通過java.io包提供了豐富的I/O類庫,支持文件操作、字節流、字符流等功能。


File類

File類是java.io包中唯一代表磁盤文件本身的對象,用于操作文件和目錄。

構造方法
  1. File(String path)

    • 根據路徑創建File對象。
  2. File(String parent, String child)

    • 根據父路徑和子路徑(包括文件名)創建File對象。
  3. File(File parent, String child)

    • 根據File對象表示的父路徑和子路徑創建File對象。

注意:路徑分隔符可以使用\\(Windows)或/(Unix/Linux)。

常用方法
  1. boolean exists()

    • 判斷文件或目錄是否存在。
  2. boolean delete()

    • 刪除文件或目錄。
  3. boolean createNewFile()

    • 如果文件不存在,則創建一個新文件。
  4. String getName()

    • 返回文件或目錄的名稱。
  5. String getPath()

    • 返回文件或目錄的路徑。
  6. String getAbsolutePath()

    • 返回文件或目錄的絕對路徑。
  7. boolean canRead()

    • 判斷文件是否可讀。
  8. boolean canWrite()

    • 判斷文件是否可寫。
  9. boolean isFile()

    • 判斷是否為文件。
  10. boolean isDirectory()

    • 判斷是否為目錄。
  11. long length()

    • 返回文件內容的長度(字節數)。
  12. String[] list()

    • 返回目錄內所有文件和子目錄的名稱。
  13. File[] listFiles()

    • 返回目錄內所有文件和子目錄的File對象。
  14. createTempFile(String prefix, String suffix)

    • 創建臨時文件。
  15. deleteOnExit()

    • JVM退出時自動刪除文件。

字節流

字節流用于處理二進制數據(如圖片、音頻、視頻等),以字節為單位進行讀寫操作。

在這里插入圖片描述

字節輸入流(InputStream)

InputStream是字節輸入流的抽象類,用于從源(如文件、網絡等)讀取數據。

常用方法

  1. int read()

    • 逐個字節讀取,返回讀取的字節值(0-255),如果到達流末尾則返回-1。
  2. int read(byte[] b)

    • 將數據讀取到字節數組b中,返回實際讀取的字節數。
  3. int read(byte[] b, int off, int len)

    • 從偏移量off開始,讀取len個字節到數組b中,返回實際讀取的字節數。
  4. void close()

    • 關閉流,釋放資源。
字節輸出流(OutputStream)

OutputStream是字節輸出流的抽象類,用于將數據寫入目標(如文件、網絡等)。

常用方法

  1. void write(int b)

    • 逐個字節寫入。
  2. void write(byte[] b)

    • 將字節數組b中的數據寫入。
  3. void write(byte[] b, int off, int len)

    • 從偏移量off開始,寫入len個字節。
  4. void flush()

    • 強制將緩沖區中的數據寫入目標。
  5. void close()

    • 關閉流,釋放資源。
具體實現類
  1. FileInputStream

    • 用于從文件中讀取字節數據。
  2. FileOutputStream

    • 用于將字節數據寫入文件。

拓展總結
  1. 文件操作

    • 使用File類可以創建、刪除、重命名文件,判斷文件是否存在,查詢文件屬性等。
  2. 字節流

    • 字節流適用于處理二進制數據,InputStreamOutputStream是字節流的抽象基類。
    • FileInputStreamFileOutputStream是常用的字節流實現類,用于文件的讀寫操作。
  3. 流的使用注意事項

    • 使用流時,務必在操作完成后調用close()方法關閉流,釋放系統資源。
    • 對于輸出流,可以調用flush()方法強制將緩沖區中的數據寫入目標。
  4. 臨時文件

    • 使用createTempFile()方法可以創建臨時文件,deleteOnExit()方法可以確保JVM退出時自動刪除臨時文件。
  5. 路徑處理

    • 路徑分隔符可以使用\\(Windows)或/(Unix/Linux),Java會自動處理。
  6. 性能優化

    • 對于大文件的讀寫,建議使用緩沖區(如BufferedInputStreamBufferedOutputStream)來提高性能。

示例代碼
文件操作
File file = new File("test.txt");
if (!file.exists()) {file.createNewFile(); // 創建文件
}
System.out.println("文件名稱: " + file.getName());
System.out.println("文件路徑: " + file.getAbsolutePath());
file.delete(); // 刪除文件AI寫代碼java運行
字節流讀寫
// 寫入文件
try (FileOutputStream fos = new FileOutputStream("output.txt")) {fos.write("Hello, World!".getBytes());fos.flush();
}// 讀取文件
try (FileInputStream fis = new FileInputStream("output.txt")) {byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) != -1) {System.out.println(new String(buffer, 0, len));}
}AI寫代碼java運行

通過掌握這些核心概念和類庫,可以高效地處理文件操作和字節流讀寫。

字符流總結

字符流是Java I/O中用于處理文本數據的流,它以字符為單位進行讀寫操作。與字節流不同,字符流專門用于處理字符數據(如文本文件),并且支持字符編碼(如UTF-8、GBK等),能夠正確處理多字節字符。


字符流概述

字符流的核心類是ReaderWriter,它們分別是字符輸入流和字符輸出流的抽象基類。字符流的主要特點包括:

  1. 以字符為單位
    • 字符流以字符為單位讀寫數據,適合處理文本文件。
  2. 支持字符編碼
    • 字符流可以正確處理字符編碼,避免亂碼問題。
  3. 高效讀寫
    • 字符流通常與緩沖區結合使用(如BufferedReaderBufferedWriter),提高讀寫效率。

在這里插入圖片描述


字符輸入流(Reader)

Reader是字符輸入流的抽象類,用于從源(如文件、字符串等)讀取字符數據。

常用方法
  1. int read()

    • 讀取單個字符,返回字符的Unicode值(0-65535),如果到達流末尾則返回-1。
  2. int read(char[] cbuf)

    • 將字符數據讀取到字符數組cbuf中,返回實際讀取的字符數。
  3. int read(char[] cbuf, int off, int len)

    • 從偏移量off開始,讀取len個字符到數組cbuf中,返回實際讀取的字符數。
  4. void close()

    • 關閉流,釋放資源。
具體實現類
  1. FileReader

    • 用于從文件中讀取字符數據。
  2. BufferedReader

    • 帶有緩沖區的字符輸入流,提供readLine()方法逐行讀取文本。
  3. InputStreamReader

    • 將字節流轉換為字符流,支持指定字符編碼。

字符輸出流(Writer)

Writer是字符輸出流的抽象類,用于將字符數據寫入目標(如文件、控制臺等)。

常用方法
  1. void write(int c)

    • 寫入單個字符。
  2. void write(char[] cbuf)

    • 寫入字符數組cbuf中的數據。
  3. void write(char[] cbuf, int off, int len)

    • 從偏移量off開始,寫入len個字符。
  4. void write(String str)

    • 寫入字符串str
  5. void write(String str, int off, int len)

    • 從偏移量off開始,寫入len個字符。
  6. void flush()

    • 強制將緩沖區中的數據寫入目標。
  7. void close()

    • 關閉流,釋放資源。
具體實現類
  1. FileWriter

    • 用于將字符數據寫入文件。
  2. BufferedWriter

    • 帶有緩沖區的字符輸出流,提供newLine()方法寫入換行符。
  3. OutputStreamWriter

    • 將字節流轉換為字符流,支持指定字符編碼。

字符流與字節流的區別
  1. 單位不同

    • 字節流以字節為單位,適合處理二進制數據。
    • 字符流以字符為單位,適合處理文本數據。
  2. 編碼支持

    • 字節流不涉及字符編碼,直接處理字節數據。
    • 字符流支持字符編碼,能夠正確處理多字節字符。
  3. 性能優化

    • 字符流通常與緩沖區結合使用,提高讀寫效率。

示例代碼
字符流讀寫文件
// 寫入文件
try (FileWriter fw = new FileWriter("output.txt");BufferedWriter bw = new BufferedWriter(fw)) {bw.write("Hello, World!");bw.newLine(); // 寫入換行符bw.write("This is a test.");
}// 讀取文件
try (FileReader fr = new FileReader("output.txt");BufferedReader br = new BufferedReader(fr)) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}
}AI寫代碼java運行
使用指定編碼讀寫文件
// 寫入文件(指定編碼為UTF-8)
try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8");BufferedWriter bw = new BufferedWriter(osw)) {bw.write("你好,世界!");
}// 讀取文件(指定編碼為UTF-8)
try (InputStreamReader isr = new InputStreamReader(new FileInputStream("output.txt"), "UTF-8");BufferedReader br = new BufferedReader(isr)) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}
}AI寫代碼java運行

總結
  1. 字符流適用場景

    • 處理文本文件、字符串等字符數據。
  2. 核心類

    • ReaderWriter是字符流的抽象基類。
    • FileReaderBufferedReaderFileWriterBufferedWriter是常用的實現類。
  3. 字符編碼

    • 使用InputStreamReaderOutputStreamWriter可以指定字符編碼,避免亂碼問題。
  4. 性能優化

    • 使用BufferedReaderBufferedWriter可以提高讀寫效率。
  5. 流關閉

    • 使用try-with-resources語法確保流被正確關閉,釋放資源。

通過掌握字符流的核心概念和類庫,可以高效地處理文本數據的讀寫操作。

十二、集合

集合是Java中用于存儲和管理一組對象的容器。它提供了一種更靈活、更高效的方式來操作數據集合。以下是集合的核心概念和總結:


集合的特點
  1. 容器性質

    • 集合是一個容器,可以容納其他類型的數據。
    • 集合不能直接存儲基本數據類型(如intchar等),也不能直接存儲對象,存儲的是Java對象的內存地址(引用)。
  2. 數據結構

    • 不同的集合對應不同的數據結構(如數組、鏈表、哈希表、二叉樹等)。
    • 使用不同的集合等同于使用了不同的數據結構。
  3. 包位置

    • 所有的集合類都位于java.util包中。

集合的層次結構
  1. 超級父接口:Iterable<T>

    • 所有集合都是可迭代的,即可以通過迭代器遍歷集合中的元素。
    • 方法:Iterator<T> iterator():返回集合的迭代器。
  2. 單個元素集合的父接口:Collection<E>

    • 表示存儲單個元素的集合的超級接口。
    • 子接口包括:ListSetQueue等。
  3. 鍵值對集合的父接口:Map<K,V>

    • 表示存儲鍵值對的集合,獨立于Collection體系。

集合的實現類總結
1. List接口的實現類
  • ArrayList
    • 底層是數組,查詢快,增刪慢。
    • 非線程安全。
  • LinkedList
    • 底層是雙向鏈表,增刪快,查詢慢。
    • 非線程安全。
  • Vector
    • 底層是數組,線程安全,但效率較低,使用較少。
2. Set接口的實現類
  • HashSet
    • 底層是HashMap,元素存儲在HashMapkey部分。
    • 無序且不允許重復。
  • TreeSet
    • 底層是TreeMap,元素存儲在TreeMapkey部分。
    • 元素自動按大小順序排序。
3. Map接口的實現類
  • HashMap
    • 底層是哈希表,非線程安全。
    • 允許null鍵和null值。
  • Hashtable
    • 底層是哈希表,線程安全,但效率較低,使用較少。
    • 不允許null鍵和null值。
  • Properties
    • 底層是哈希表,線程安全。
    • keyvalue只能存儲字符串(String)。
  • TreeMap
    • 底層是二叉樹。
    • key自動按照大小順序排序。

集合的選擇
  1. 需要存儲單個元素

    • 如果需要有序且允許重復,使用List
      • 查詢多,增刪少:ArrayList
      • 增刪多,查詢少:LinkedList
    • 如果不需要重復元素,使用Set
      • 無序:HashSet
      • 有序:TreeSet
  2. 需要存儲鍵值對

    • 非線程安全:HashMap
    • 線程安全:HashtableProperties
    • 需要排序:TreeMap
  3. 線程安全

    • 如果需要線程安全,可以使用VectorHashtableProperties,但效率較低。
    • 推薦使用Collections.synchronizedList()ConcurrentHashMap等并發集合。

總結
  1. 集合的核心

    • 集合是存儲和管理一組對象的容器,存儲的是對象的內存地址。
    • 不同的集合對應不同的數據結構,選擇合適的集合可以提高程序效率。
  2. 常用集合

    • List:有序且允許重復,常用ArrayListLinkedList
    • Set:無序且不允許重復,常用HashSetTreeSet
    • Map:存儲鍵值對,常用HashMapTreeMapProperties
  3. 線程安全

    • 線程安全的集合有VectorHashtableProperties,但效率較低。
    • 推薦使用并發集合(如ConcurrentHashMap)來實現線程安全。

通過掌握集合的核心概念和常用實現類,可以更高效地處理數據集合,并根據需求選擇合適的集合類型。

List 集合存儲元素的特點:

有序可重復

有序:存進去的順序和取出的順序相同,每一個元素都有下標

可重復:存進去1,可以再存儲一個1

Set 集合存儲元素的特點(Map的Key):

無序不可重復

無序:存進去的順序和取出的順序不一定相同,另外 Set 集合中元素沒有下標(哈希表的存儲)

不可重復:存進去1,不能再存儲1了(哈希表的覆蓋)

SortedSet( SortedMap )集合存儲元素特點:

首先是無序不可重復的,但是 SortedSet 集合中的元素是可排序的

無序:存進去的順序和取出的順序不一定相同,另外 Set 集合中元素沒有下標

不可重復:存進去1,不能再存儲1了

可排序:可以按照大小順序排列。

Map 集合的 key ,就是一個 Set 集合。

往 Set 集合中放數據,實際上放到了 Map 集合的 key 部分。

Interface Collection

沒有使用泛型前可以存儲Object的所有子類型

  • Boolean add(E e) 添加元素
  • Object[] toArray() 轉化成數組(使用不多)
  • Int size() 返回此集合中元素的數目。
  • Boolean contains(Object o) 如果此集合包含指定的元素(存放在集合中的類型,需要重寫equals方法)
  • Void clear() 從此集合中刪除所有元素
  • Boolean equals(Object o) 將指定的對象與此集合進行比較以實現相等性(內存地址)
  • Boolean remove(Object o) 從此集合中刪除指定元素的單個實例
  • Boolean isEmpty() 如果此集合不包含任何元素(判空)則返回。true

Iterator<E> iterator() ***:**不管存進去什么,拿出來都是Object,取出來還是原類型

返回此集合中元素的迭代器**,Collection通用,Map集合不能用**

只要集合結構發生改變迭代器一定要重新獲取

  • default void forEachRemaining(Consumer<? super E> action) 對每個剩余元素執行給定的操作,直到所有元素都已處理完畢或該操作引發異常。
  • Boolean hasNext() 如果迭代具有更多元素,則返回。true
  • Object next() 返回迭代中的下一個元素。(返回object)
  • default void remove() 從基礎集合中刪除此迭代器返回的最后一個元素(可選操作)。
Interface List 有序可重復,Collection子接口
  • void add(int index, E element) 在此列表中的指定位置插入指定的元素
  • E get(int index) 返回此列表中指定位置處的元素
  • E set(int index, E element) 將此列表中指定位置的元素替換為指定的元素
  • int indexOf(Object o) 返回此列表中指定元素的第一次出現的索引,如果此列表不包含該元素,則返回 -1
  • int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出現的索引,如果此列表不包含該元素,則返回 -1。
  • E remove(int index) 刪除此列表中指定位置的元素
Class ArrayList 非線程安全數組,初始化容量10,底層object數組

構造方法:

  • ArrayList() 構造初始容量為 10 的空列表(底層先創建了一個長度為0的數組,添加元素是初始化為10,自動擴容1.5倍)
  • ArrayList(int initialCapacity) 構造具有指定初始容量的空列表(建議提前估計,減少擴容)
  • ArrayList(Collection<? extends E> c) 構造一個列表,其中包含指定集合的元素,并按集合的迭代器返回這些元素的順序排列。

方法:同List方法

Class LinkedList 雙向鏈表,隨機增刪效率高,檢索效率低
Class Vector 線程安全數組,默認10,擴容翻倍**(不經常使用)**

轉換:使用集合工具類:java.util.Collections.synchronizedList(集合)

Interface Set 無序不可重復 存儲Map的Key

Class HashSet 哈希表(底層HashMap)

需要重寫hashCode和equals方法,其他方法參見HashMap

Interface SortedSet 無序不可重復可排序

Class TreeSet 二叉樹(底層TreeMap Key部分)無序不可重復可排序

Key值自定義類需要實現java.long.Comparable接口或者創建比較器對象

class user implements Comparable<user>{      //自定義類需要實現接口int age;public user(int age) {this.age = age;}@Overridepublic String toString() {return "user{" + "age=" + age + '}';}@Override         //重寫比較規則public int compareTo(user o) {return this.age-o.age;    //返回==0,value覆蓋,返回大于0 到右子樹,返回小于0到左子樹}
}AI寫代碼java運行
Interface Map<K,V> Map主接口(和Collection沒有繼承關系)

以Key和Value存儲數據都是引用數據類型,都存儲內存地址,Key是主導

  • V put(K key, V value) 添加鍵值對(Key元素需要重新hashCode和equals方法)(Key可以為空,只有一個)
  • void clear() 清空Map集合
  • V get(Object key) 通過key獲取value(key元素需要重新hashCode和equals方法)
  • boolean containsKey(Object key) 判斷Map是否包含某個key(底層equals)
  • boolean containsValue(Object value) 判斷Map是否包含某個value(底層equals)
  • boolean isEmpty() 判斷Map集合元素個數是否為零
  • Set<K> keySet() 獲取Map集合所有的Key(是個set集合)
  • V remove(Object key) 通過key刪除鍵值對
  • Collection<V> values() 獲取Map集合中鍵值對所有value(返回Collection)
  • int size() 獲取Map集合所有的鍵值對個數
Set<Map.Entry<Integer,String>>set1=m.entrySet();       //使用方法
Iterator<Map.Entry<Integer,String>> it=set1.iterator(); //獲取迭代器
while (it.hasNext()) {Map.Entry<Integer, String> entry = it.next();System.out.println(entry);     //直接遍歷Integer key = entry.getKey();    //獲取鍵String value = entry.getValue();    //獲取值System.out.println(key + "=" + value);   //分開遍歷for(Map.Entry<Integer,String> node:set1)   //效率較高,適合大數據,直接獲取System.out.println(node);     //組合遍歷AI寫代碼java運行
Class HashMap<K,V> 哈希表 非線程安全(初始化容量16[必須是2的倍數],默認加載因子0.75)

Key元素類型需要重新hashCode和equals方法

JDK8新特性:當單向鏈表長度超過8后數據結構會變成紅黑樹數據結構,當紅黑樹小于6,會變回鏈表

構造 函數 描述

  • HashMap() 使用默認初始容量 (16) ,默認負載系數 (0.75)
  • HashMap(int initialCapacity) 指定的初始容量,默認負載系數 初始容量必須是2的倍數:達到散列均勻,提高存取效率
  • HashMap(int initialCapacity, float loadFactor) 指定初始容量和負載系數
  • HashMap(Map<? extends K,? extends V> m)
Class Hashtable<K,V> 哈希表 線程安全(synchronized) Key不可以為空*(不常用)**

初始化容量11,默認加載因子0.75f,擴容:原容量*2+1

Class Properties 屬性類 繼承Hashtable類 僅支持String

  • Object setProperty(String key, String value) 存
  • String getProperty(String key) 取
  • String getProperty(String key, String defaultValue) 當key值為NULL時,返回def的值;當key值不為NULL時,返回key的值
Interface SortedMap<K,V>

Class TreeMap<K,V> 二叉樹 可排序集合(中序遍歷)

Key值自定義類需要實現java.long.Comparable接口或者創建比較器對象(類或者匿名內部類)

Class Collections 集合工具類
  • synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(線程安全)映射。
  • synchronizedList(List list) 返回由指定列表支持的同步(線程安全)列表。**
    **synchronizedCollection(Collection c) 返回由指定集合支持的同步(線程安全)集合
  • sort(List list, Comparator<? super T> c) 根據指定比較器引發的順序對指定列表進行排序。

十三、泛型

1. 泛型概述
  • 引入時間:JDK 5.0 之后的新特性。

  • 作用

    • 統一集合中元素的類型,避免類型轉換錯誤。
    • 只在程序編譯階段起作用,編譯后會進行類型擦除(Type Erasure)。
  • 語法

    • 在創建對象時,前后兩段添加泛型類型。

    • 示例:

      List<String> list = new ArrayList<String>();AI寫代碼java運行
      

2. 泛型的優點
  • 類型安全:編譯時檢查類型,避免運行時類型轉換錯誤。
  • 代碼復用:可以編寫通用的類和方法,適用于多種類型。
  • 代碼簡潔:減少強制類型轉換的代碼。

3. 泛型的缺點
  • 導致集合存儲缺少多樣性:泛型限制了集合中元素的類型,無法存儲多種類型的對象。
  • 類型擦除:泛型信息在編譯后會被擦除,運行時無法獲取泛型的具體類型。

4. 自動推斷機制(鉆石表達式)
  • 引入時間:JDK 7 新特性。

  • 作用:自動推斷泛型類型,簡化代碼。

  • 語法:只寫前面的泛型類型,后面的泛型類型可以省略。

  • 示例

    List<String> list = new ArrayList<>();AI寫代碼java運行
    

5. 自定義泛型
  • 泛型類

    • 在定義類時添加 <T>T 是類型參數。

    • 示例:

      public class Box<T> {private T value;public void setValue(T value) {this.value = value;}public T getValue() {return value;}
      }AI寫代碼java運行
      
    • 使用:

      Box<String> box = new Box<>();
      box.setValue("Hello");
      String value = box.getValue();AI寫代碼java運行
      
  • 泛型方法

    • 在定義方法時添加 <T>T 是類型參數。

    • 示例:

      public <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}
      }AI寫代碼java運行
      
    • 使用:

      Integer[] intArray = {1, 2, 3};
      printArray(intArray);AI寫代碼java運行
      

6. 泛型的通配符
  • <?>:表示任意類型。

  • <? extends T>:表示 T 或其子類型(上界通配符)。

  • <? super T>:表示 T 或其父類型(下界通配符)。

  • 示例:

    public void printList(List<?> list) {for (Object element : list) {System.out.println(element);}
    }AI寫代碼java運行
    

7. 泛型的限制
  • 不能使用基本類型:泛型類型必須是引用類型(如 Integer 而不是 int)。
  • 不能創建泛型數組:例如 new T[10] 是非法的。
  • 不能實例化泛型類型:例如 new T() 是非法的。

8. 泛型的應用場景
  • 集合框架:如 List<T>Map<K, V> 等。
  • 工具類:如 Comparator<T>Comparable<T> 等。
  • 自定義數據結構:如棧、隊列、鏈表等。

總結與拓展
  • 泛型的作用:統一集合中元素的類型,提高代碼的安全性和復用性。
  • 自動推斷機制:JDK 7 引入的鉆石表達式簡化了泛型代碼。
  • 自定義泛型:通過泛型類和泛型方法實現通用代碼。
  • 通配符<?><? extends T><? super T> 提供了更靈活的類型約束。
  • 限制:泛型不能使用基本類型、不能創建泛型數組、不能實例化泛型類型。

十四、多線程

進程是:一個應用程序(1個進程是一個軟件)

獨立性:系統分配資源和調度資源的獨立單位

動態性:進程實質是程序的一次執行過程,進程是動態產生,動態消亡的

并發性:任何進程都可以同其他進程一起并發執行

線程是:一個進程中的執行場景/執行單元,是進程中單個順序控制流,是一條執行路徑。

并行:同一時刻,多個指令在多個CPU上同時執行

并發:同一時刻,多個指令在單個CPU交替執行

線程狀態轉換

在這里插入圖片描述

1、新建狀態(New):新創建了一個線程對象。

2、就緒狀態(Runnable):線程對象創建后,其他線程調用了該對象的start()方法。該狀態的線程位于可運行線程池中,變得可運行,等待獲取CPU的使用權。

3、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。

4、阻塞狀態(Blocked):阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:

(一)、等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。(wait會釋放持有的鎖)

(二)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。

(三)、其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態

當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。(注意,sleep是不會釋放持有的鎖)

5、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

線程構造方法

構造方法名備注
Thread()
Thread(String name)name為線程名字
創建線程第二種方式
Thread(Runnable target)
Thread(Runnable target, String name)name為線程名字
Java 中實現線程的三種方式總結

1. 繼承 Thread
  • 實現方式

    • 編寫一個類,直接繼承 java.lang.Thread
    • 重寫 run() 方法,定義線程執行的任務。
  • 創建線程對象

    MyThread thread = new MyThread();AI寫代碼java運行
    
  • 啟動線程

    thread.start();AI寫代碼java運行
    
  • 特點

    • 簡單易用,但 Java 是單繼承,繼承 Thread 類后無法繼承其他類。

2. 實現 Runnable 接口
  • 實現方式

    • 編寫一個類,實現 java.lang.Runnable 接口。
    • 實現 run() 方法,定義線程執行的任務。
    • 通常使用匿名內部類創建。
  • 創建線程對象

    Runnable task = new MyRunnable();
    Thread thread = new Thread(task);AI寫代碼java運行
    
  • 啟動線程

    thread.start();AI寫代碼java運行
    
  • 特點

    • 更靈活,可以避免單繼承的限制。
    • 適合多個線程共享同一個任務。

3. 使用 CallableFuture 接口
  • 實現方式

    • 編寫一個類,實現 java.util.concurrent.Callable 接口。
    • 實現 call() 方法,定義線程執行的任務,并返回結果。
  • 創建線程對象

    1. 創建 Callable 實現類的實例:

      Callable<Integer> task = new MyCallable();AI寫代碼java運行
      
    2. 使用 FutureTask 包裝 Callable 對象:

      FutureTask<Integer> futureTask = new FutureTask<>(task);AI寫代碼java運行
      
    3. 使用 FutureTask 對象作為 Threadtarget 創建線程:

      Thread thread = new Thread(futureTask);AI寫代碼java運行
      
  • 啟動線程

    thread.start();AI寫代碼java運行
    
  • 獲取結果

    Integer result = futureTask.get(); // 阻塞直到獲取結果AI寫代碼java運行
    
  • 特點

    • call() 方法可以有返回值和拋出異常。
    • 適合需要獲取線程執行結果的場景。

Future 接口的常用方法
  • cancel(boolean mayInterruptIfRunning):嘗試取消任務。
  • get():獲取任務結果,阻塞直到任務完成。
  • get(long timeout, TimeUnit unit):在指定時間內獲取任務結果,超時拋出 TimeoutException
  • isCancelled():判斷任務是否被取消。
  • isDone():判斷任務是否完成。

三種方式的對比
方式優點缺點
繼承 Thread簡單易用單繼承限制,無法繼承其他類
實現 Runnable 接口靈活,避免單繼承限制,適合多線程共享任務無法直接獲取線程執行結果
使用 CallableFuture可以獲取線程執行結果,支持異常處理,功能更強大使用稍復雜,需要 FutureTask 包裝

總結
  • 繼承 Thread:適合簡單的線程任務,但受限于單繼承。
  • 實現 Runnable 接口:更靈活,適合多線程共享任務。
  • 使用 CallableFuture:適合需要獲取線程執行結果或處理異常的場景。

根據具體需求選擇合適的方式實現多線程編程。

獲取當前線程對象、獲取線程對象名字、修改線程對象名字

方法名作用
static Thread currentThread()獲取當前線程對象
String getName()獲取線程對象名字
void setName(String name)修改線程對象名字

關于線程的sleep方法

方法名作用
static void sleep(long millis)讓當前線程休眠millis秒

關于線程中斷sleep()的方法

方法名作用
void interrupt()終止線程的睡眠
Java進程的優先級
常量名備注
static int MAX_PRIORITY最高優先級(10)
static int MIN_PRIORITY最低優先級(1)
static int NORM_PRIORITY默認優先級(5)

方法:

方法名作用
int getPriority()獲得線程優先級
void setPriority(int newPriority)設置線程優先級
static void yield()讓位,當前線程暫停,回到就緒狀態,讓給其它線程。
void join()將一個線程合并到當前線程中,當前線程受阻塞,加入的線程執行直到結束
void join(long millis)接上條,等待該線程終止的時間最長為 millis 毫秒
void join(long millis, int nanos)接第一條,等待該線程終止的時間最長為 millis 毫秒 + nanos 納秒

多線程并發環境下,數據的安全問題(重點)

1.為什么這個是重點?

以后在開發中,我們的項目都是運行在服務器當中,而服務器已經將線程的定義,線程對象的創建,線程的啟動等,都已經實現完了。這些代碼我們都不需要編寫。

最重要的是: 你要知道,你編寫的程序需要放到一個多線程的環境下運行,你更需要關注的是這些數據在多線程并發的環境下是否是安全的。(重點:★★★★★)

2.什么時候數據在多線程并發的環境下會存在安全問題呢?★★★★★

滿足三個條件:

條件1:多線程并發。

條件2:有共享數據。

條件3:共享數據有修改的行為。

滿足以上3個條件之后,就會存在線程安全問題。

3.怎么解決線程安全問題呢?

當多線程并發的環境下,有共享數據,并且這個數據還會被修改,此時就存在線程安全問題,怎么解決這個問題?

線程排隊執行。(不能并發)。用排隊執行解決線程安全問題。

這種機制被稱為:線程同步機制。專業術語叫做:線程同步,實際上就是線程不能并發了,線程必須排隊執行。

線程同步就是線程排隊了,線程排隊了就會 犧牲一部分效率 ,數據安全第一位,只有數據安全了,我們才可以談效率。數據不安全,沒有效率的事兒。

死鎖(DeadLock)

死鎖(Deadlock)是多線程編程中的一種常見問題,指的是兩個或多個線程在執行過程中,因為爭奪資源而造成的一種互相等待的現象,導致這些線程都無法繼續執行下去。

死鎖代碼要會寫。一般面試官要求你會寫。只有會寫的,才會在以后的開發中注意這個事兒。因為死鎖很難調試。


死鎖的四個必要條件

死鎖的發生必須同時滿足以下四個條件:

  1. 互斥條件(Mutual Exclusion)

    • 資源一次只能被一個線程占用。
  2. 占有并等待(Hold and Wait)

    • 線程已經占有了至少一個資源,但又申請新的資源,而新的資源被其他線程占用。
  3. 不可搶占(No Preemption)

    • 線程已占有的資源不能被其他線程強行搶占,必須由線程自己釋放。
  4. 循環等待(Circular Wait)

    • 存在一個線程的等待循環鏈,每個線程都在等待下一個線程所占用的資源。

Java 中的死鎖示例

以下是一個經典的死鎖代碼示例,展示了兩個線程互相等待對方釋放鎖的情況:

public class DeadlockExample {private static final Object lock1 = new Object();private static final Object lock2 = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (lock1) {System.out.println("Thread 1: Holding lock 1...");try {Thread.sleep(100); // 模擬操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 1: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread 1: Acquired lock 2!");}}});Thread thread2 = new Thread(() -> {synchronized (lock2) {System.out.println("Thread 2: Holding lock 2...");try {Thread.sleep(100); // 模擬操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 2: Waiting for lock 1...");synchronized (lock1) {System.out.println("Thread 2: Acquired lock 1!");}}});thread1.start();thread2.start();}
}AI寫代碼java運行
代碼分析
  1. 線程1

    • 先獲取lock1,然后嘗試獲取lock2
    • 在獲取lock2之前,線程1會休眠100毫秒。
  2. 線程2

    • 先獲取lock2,然后嘗試獲取lock1
    • 在獲取lock1之前,線程2會休眠100毫秒。
  3. 死鎖發生

    • 線程1持有lock1并等待lock2
    • 線程2持有lock2并等待lock1
    • 兩個線程互相等待,導致死鎖。

如何避免死鎖
  1. 避免嵌套鎖

    • 盡量不要在持有一個鎖的同時去申請另一個鎖。
  2. 按順序獲取鎖

    • 如果多個線程需要獲取多個鎖,確保它們以相同的順序獲取鎖。
  3. 使用超時機制

    • 在獲取鎖時設置超時時間,如果超時則釋放已持有的鎖并重試。
  4. 使用工具檢測

    • 使用工具(如jstack)檢測死鎖。

死鎖的調試與檢測
  1. 使用jstack

    • 運行程序后,使用jstack命令查看線程狀態,可以檢測到死鎖。
  2. 日志輸出

    • 在代碼中添加日志,記錄鎖的獲取和釋放情況。
  3. 使用工具

    • 使用IDE(如IntelliJ IDEA)或第三方工具(如VisualVM)檢測死鎖。

守護線程

在Java中,線程分為兩大類:用戶線程守護線程。守護線程(Daemon Thread)是一種特殊的線程,它的生命周期依賴于用戶線程。當所有的用戶線程結束時,守護線程會自動退出。


守護線程的特點
  1. 依賴用戶線程

    • 守護線程是為用戶線程提供服務的線程。
    • 當所有的用戶線程結束時,守護線程會自動退出。
  2. 典型代表

    • 垃圾回收線程(GC)是Java中最典型的守護線程。
  3. 主線程是用戶線程

    • main方法所在的線程是用戶線程。
  4. 死循環

    • 守護線程通常是一個死循環,持續執行某些后臺任務。

守護線程的應用場景
  1. 定時任務

    • 例如,每天00:00自動備份系統數據。
    • 可以使用定時器(如TimerScheduledExecutorService),并將定時任務設置為守護線程。
  2. 后臺監控

    • 例如,監控系統資源使用情況、日志清理等。
  3. 垃圾回收

    • Java的垃圾回收線程就是一個守護線程。

守護線程的設置

在Java中,可以通過setDaemon(boolean on)方法將一個線程設置為守護線程:

方法簽名說明
void setDaemon(boolean on)ontrue表示將線程設置為守護線程

注意

  • 必須在調用start()方法之前設置守護線程,否則會拋出IllegalThreadStateException
  • 守護線程中創建的子線程默認也是守護線程。

代碼示例

以下是一個守護線程的示例,展示了如何設置守護線程以及它的行為:

public class DaemonThreadExample {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("守護線程正在運行...");try {Thread.sleep(1000); // 模擬任務執行} catch (InterruptedException e) {e.printStackTrace();}}});// 設置為守護線程daemonThread.setDaemon(true);// 啟動守護線程daemonThread.start();// 主線程(用戶線程)執行任務System.out.println("主線程開始執行...");try {Thread.sleep(5000); // 模擬主線程執行任務} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主線程執行完畢,程序退出。");}
}AI寫代碼java運行
代碼分析
  1. 守護線程

    • 守護線程是一個死循環,每隔1秒輸出一條消息。
    • 設置為守護線程后,當主線程結束時,守護線程會自動退出。
  2. 主線程

    • 主線程執行5秒后結束。
    • 主線程結束后,守護線程也會自動退出。

守護線程的注意事項
  1. 資源釋放

    • 守護線程中不要執行關鍵任務(如文件寫入、數據庫操作等),因為它的退出是不可控的。
  2. 線程優先級

    • 守護線程的優先級通常較低,適合執行后臺任務。
  3. 生命周期

    • 守護線程的生命周期依賴于用戶線程,不能獨立存在。

定時器的作用:

間隔特定的時間,執行特定的程序。在實際的開發中,每隔多久執行一段特定的程序,這種需求是很常見的,那么在java中其實可以采用多種方式實現:

可以使用sleep方法,睡眠,設置睡眠時間,沒到這個時間點醒來,執行任務。這種方式是最原始的定時器。(比較low)

在java的類庫中已經寫好了一個定時器:java.util.Timer,可以直接拿來用。

不過,這種方式在目前的開發中也很少用,因為現在有很多高級框架都是支持定時任務的。

在實際的開發中,目前使用較多的是Spring框架中提供的SpringTask框架,這個框架只要進行簡單的配置,就可以完成定時器的任務。

構造方法名備注
Timer()創建一個定時器
Timer(boolean isDaemon)isDaemon為true為守護線程定時器
Timer(String name)創建一個定時器,其線程名字為name
Timer(String name, boolean isDaemon)結合2、3
方法名作用
void schedule(TimerTask task, Date firstTime, long period)安排指定的任務在指定的時間開始進行重復的固定延遲執行
void cancel()終止定時器
關于Object類的wait()、notify()、notifyAll()方法
方法名作用
void wait()讓活動在當前對象的線程無限等待(釋放之前占有的鎖)
void notify()喚醒當前對象正在等待的線程(只提示喚醒,不會釋放鎖)
void notifyAll()喚醒當前對象全部正在等待的線程(只提示喚醒,不會釋放鎖)

wait和notify方法不是線程對象的方法,是java中任何一個java對象都有的方法,因為這兩個方法是 Object類中自帶 的。

wait方法和notify方法不是通過線程對象調用

調用:

Object o = new Object();

o.wait();

總結 ★★★★★(呼應生產者消費者模式)

1、wait和notify方法不是線程對象的方法,是普通java對象都有的方法。

2、wait方法和notify方法建立在 線程同步 的基礎之上。因為多線程要同時操作一個倉庫。有線程安全問題。

3、wait方法作用:o.wait() 讓正在o對象上活動的線程t進入等待狀態,并且釋放掉t線程之前占有的o對象的鎖

4、notify方法作用:o.notify() 讓正在o對象上等待的線程喚醒,只是通知,不會釋放o對象上之前占有的鎖。

生產者消費者模式(wait()和notify())

什么是“生產者和消費者模式”?

生產線程負責生產,消費線程負責消費。

生產線程和消費線程要達到均衡。

這是一種特殊的業務需求,在這種特殊的情況下需要使用wait方法和notify方法。

模擬一個業務需求

倉庫我們采用List集合。

List集合中假設只能存儲1個元素。

1個元素就表示倉庫滿了。

如果List集合中元素個數是0,就表示倉庫空了。

保證List集合中永遠都是最多存儲1個元素。

必須做到這種效果:生產1個消費1個。

在這里插入圖片描述

十五、反射

1. Class 對象概述
  • Class 對象:在 Java 中,每個類在加載到內存時都會生成一個 Class 對象,該對象存儲了類的所有信息(如方法、構造函數、字段等)。
  • 反射:通過 Class 對象,可以在運行時動態獲取類的信息并操作類的成員(如調用方法、訪問字段等)。

2. Class 對象的生成方式
  1. 類名.class

    • JVM 將類加載到內存中,但不進行初始化。

    • 返回該類的 Class 對象。

    • 示例:

      Class<?> clazz = String.class;AI寫代碼java運行
      
  2. Class.forName("包名.類名")

    • 加載類并默認進行靜態初始化。

    • 返回該類的 Class 對象。

    • 示例:

      Class<?> clazz = Class.forName("java.lang.String");AI寫代碼java運行
      
  3. Class.forName("包名.類名", false, 類加載器)

    • 第二個參數為 false 時,不進行初始化;為 true 時,進行初始化。

    • 示例:

      Class<?> clazz = Class.forName("java.lang.String", false, ClassLoader.getSystemClassLoader());AI寫代碼java運行
      
  4. 實例對象.getClass()

    • 對類進行靜態初始化和非靜態初始化。

    • 返回運行時實際對象所屬類的 Class 對象。

    • 示例:

      String str = "Hello";
      Class<?> clazz = str.getClass();AI寫代碼java運行
      

3. Class 對象的特性
  • 父子類 Class 對象不一致
    • 如果 AB 的子類,則 A.classB.class 返回的 Class 對象不同。
    • 如果 aA 的實例,則 A.classa.getClass() 返回的 Class 對象一致。

4. Class 類的常用方法
  • getName():返回類的全限定名(包名 + 類名)。
  • getSuperclass():返回類的直接父類的 Class 對象。
  • getInterfaces():返回類實現的所有接口的 Class 數組。
  • isArray():判斷該類是否是數組類型。
  • isEnum():判斷該類是否是枚舉類型。
  • isInterface():判斷該類是否是接口。
  • isPrimitive():判斷該類是否是基本類型(如 intboolean 等)。
  • isAssignableFrom(Class cls):判斷該類是否是 cls 的父類或父接口。
  • getComponentType():如果該類是數組類型,返回數組的組件類型。
  • asSubclass(Class clazz):將當前 Class 對象轉換為 clazz 的子類類型。

5. asSubclass 方法的使用
  • 作用:將當前 Class 對象轉換為指定類的子類類型。

  • 示例

    List<String> strList = new ArrayList<>();
    Class<? extends List> strListCast = strList.getClass().asSubclass(List.class);AI寫代碼java運行
    
  • 動態加載時的應用

    Class.forName("xxx.xxx.xxx").asSubclass(List.class).newInstance();AI寫代碼java運行
    
    • 如果 xxx.xxx.xxxList 的子類,則正常執行;否則拋出 ClassCastException

6. 靜態加載與動態加載
  • 靜態加載:通過 new ClassName() 加載類,編譯時必須提供類的定義。
  • 動態加載:通過 Class.forName("ClassName") 加載類,編譯時可以缺席,運行時按需提供。

總結
  • Class 對象:存儲類的所有信息,是反射機制的核心。
  • 生成方式類名.classClass.forName()實例對象.getClass()
  • 常用方法getName()getSuperclass()getInterfaces()asSubclass() 等。
  • asSubclass:用于將 Class 對象轉換為指定類的子類類型。
  • 靜態加載與動態加載:靜態加載在編譯時提供類定義,動態加載在運行時按需提供。

通過掌握 Class 對象和反射機制,可以在運行時動態操作類的成員,實現靈活的編程。

十六、小游戲(進擊的小鳥)

public class StartGame {           //游戲開始類public static void main(String[] args) throws InterruptedException {JFrame jFrame = new JFrame("進擊の小鳥");  //創建窗口對象jFrame.setSize(400,600);//窗口大小jFrame.setLocationRelativeTo(null); //窗口相對位置jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設定點擊關閉結束程序?    BirdGame birdGame = new BirdGame();  //初始化游戲對象類
?    jFrame.add(birdGame);         //把創建好的對象加進來
?    jFrame.setVisible(true);       //讓窗口可視化
?    birdGame.action();          //地面運動方法}
}AI寫代碼java運行
public class Bird {public BufferedImage images[];public BufferedImage image;   //存放小鳥圖片public int x;public int y;public int width;public int height;public int index=0;public double speed=0;    //小鳥初始速度public double upspeed=30;  //初始上拋速度public double s=0;      //經過t,發生的位移public double t=0.2;     //發生位移時間public double g=9.8;     //重力加速度public Bird() throws IOException {x=120;y=120;images=new BufferedImage[8];image= ImageIO.read(getClass().getResource("0.png"));width=image.getWidth();height=image.getHeight();for (int i=0;i<images.length;i++) {images[i] = ImageIO.read(getClass().getResource(i+".png"));}}public void fly(){      //小鳥飛飛index++;image=images[index/2%8];}public void upSpeed(){    //鼠標點擊游戲屏幕,給小鳥一個初始上拋速度speed=upspeed;}public void distanceChange(){  //實現小鳥速度,位移,縱坐標變化double v=speed; //初始速度s=v*t-g*t*t/2;  //經過t小鳥的位移speed=v-g*t;   //小鳥經過時間t的末速度y=y-(int)s;      //經過時間t后,小鳥的y}
}AI寫代碼java運行
public class Column {    //管道類public BufferedImage cImage;public int x;public  int y;public int width;public int height;public  int distance=270;  //兩根管道之間的距離public static  int count=0;Random random = new Random();public Column() throws IOException {cImage= ImageIO.read(getClass().getResource("column.png"));x=450+distance*count;width=cImage.getWidth();   //獲得管道的寬height=cImage.getHeight();  //高y=-( height/2-random.nextInt(300)-50);count++;}public void step(){x-=5; //讓地面往左運動if (x<=-width/2){x=x+distance*2;y=-(height/2-random.nextInt(300)-50) ;//x=400;}}
}AI寫代碼java運行
public class Ground {  //地面類public BufferedImage image; //存放地面圖片public int x;public int y;public Ground() {?    try {
?      x=0;
?      y=500;
?      image= ImageIO.read(getClass().getResource("ground.png"));
?    } catch (IOException e) {
?      e.printStackTrace();
?    }}public void step(){
?    x-=1; //讓地面往左運動
?    if (x==-100){
?      x=0;
?    }}
}AI寫代碼java運行
public class Music implements Runnable {    //音樂類Player player=null;@Overridepublic void run() {InputStream resourceAsStream = this.getClass().getResourceAsStream("2.mp3");try {player=new Player(resourceAsStream);player.play();} catch (JavaLayerException e) {e.printStackTrace();}}public void stopBGM(){if (player!=null)player.close();}
}AI寫代碼java運行
public class Score {  //連接對象private String sid;private int score;private String time;public String getSid() {return sid;}public void setSid(String sid) {this.sid = sid;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}
}AI寫代碼java運行
public class ScoreManager {   //jdbc連接static{try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}public List<Score> selectAllScore(){     //查詢方法List<Score> list = new ArrayList<>();?    try {
?      String sql="select * from score order by time";
?      Connection conn = DriverManager.getConnection("jdbc:mysql://cdb-kthncrwi.bj.tencentcdb.com:10159/flybird?useUnicode=true", "student", "521qianfeng");
?      PreparedStatement pst = conn.prepareStatement(sql);
?      ResultSet resultSet = pst.executeQuery();
?      while (resultSet.next()){
?        Score score = new Score();
?        score.setSid(resultSet.getString("sid"));
?        score.setScore(resultSet.getInt("score"));
?        score.setTime(resultSet.getString("time"));
?        list.add(score);
?      }
?    } catch (SQLException e) {
?      e.printStackTrace();
?    }?    return list;}public int insertScore(int score) {     //插入方法
?    int num = 0;
?    String sql = "insert into score(sid,score,time) value(?,?,?)";
?    try {
?      Connection conn = DriverManager.getConnection("jdbc:mysql://cdb-kthncrwi.bj.tencentcdb.com:10159/flybird?useUnicode=true", "student", "521qianfeng");
?      PreparedStatement pst = conn.prepareStatement(sql);
?      String sid= UUID.randomUUID().toString();     //隨機生成id
?      pst.setString(1,sid);
?      pst.setInt(2,score);
?      Date date = new Date();
?      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     //創建時間類型對象
?      String time=simpleDateFormat.format(date);
?      pst.setString(3,time);
?      num=pst.executeUpdate();
?    } catch (SQLException e) {
?      e.printStackTrace();
?    }
?    return num;}
}AI寫代碼java運行
public class BirdGame extends JPanel {   //自定義面板類繼承面板類ScoreManager sc=new ScoreManager();public JPanel jp=new JPanel();public BufferedImage bg;         //圖片緩沖區(在顯示圖片前對圖片進行操作 eg:.getWidth()寬,.getHeight()高)public BufferedImage startbg;public BufferedImage overbg;public Ground ground;public Bird bird;public Column columns[];public Music music;String file="H:\\Java程序\\小程序\\src\\小鳥\\png\\bg.png";public int state; //表示游戲狀態public static final int START=0;   //開始public static final int RUNNING=1;  //運行public static final int GAMEOVER=2; //結束public static int score=0;      //初始積分public BirdGame(){try {state=START;         //游戲初始為游戲開始狀態ground=new Ground();     //創建地面類對象,調用地面類構造方法bird = new Bird();columns=new Column[2];music = new Music();for (int i=0;i<columns.length;i++){columns[i]=new Column();}bg= ImageIO.read(getClass().getResource("bg.png")); //讀取這張圖片并把圖片值賦給變量//bg=ImageIO.read(new File(file));//bg=ImageIO.read(new File("src/小鳥/png/bg.png"));startbg=ImageIO.read(getClass().getResource("start.png"));overbg=ImageIO.read(getClass().getResource("gameover.png"));} catch (IOException e) {e.printStackTrace();}}@Overridepublic void paint(Graphics g) {         //繪制一次的畫畫方法super.paint(g);               //調用畫筆g.drawImage(bg,0,0,null);            //繪制背景(最后一個參數為觀察者switch (state){case START://繪制游戲開始圖片settishi(g);g.drawImage(startbg,0,0,null);?        break;
?      case RUNNING:
?        for (int i=0;i<columns.length;i++) {
?          g.drawImage(columns[i].cImage, columns[i].x, columns[i].y, null);
?        }
?        break;
?      case GAMEOVER:
?        //繪制游戲結束圖片
?        settishi2(g);
?        g.drawImage(overbg,0,0,null);?        break;?    }
?    g.drawImage(ground.image,ground.x,ground.y,null);  //繪制地面
?    g.drawImage(bird.image,bird.x, bird.y,null);     //繪制小鳥?    setScore(g);}public boolean isHitGround(){      //撞擊地面
?    if (bird.y+bird.height>500){
?      return true;
?    }else {
?      return false;
?    }}public boolean isHitSky(){      //撞擊天空
?    if (bird.y<0){
?      return true;
?    }else {
?      return false;
?    }}public boolean isguandao(Column c) {
?    if (bird.x + bird.width >= c.x && c.x + c.width >= bird.x) {   //撞擊管道左右
?      if (bird.y <= c.height / 2 + c.y - 72 || bird.y + bird.height >= c.height / 2 + c.y + 72) {
?        return true;
?      } else {
?        return false;
?      }?    } else {
?      return false;
?    }}public void setScore(Graphics g){               //繪制分數方法Font font = new Font(Font.SERIF, Font.ITALIC, 40);  //羅馬字體,斜體,40號g.setFont(font);     //獲取字體g.setColor(Color.white);//獲取顏色g.drawString(score+"分",40,60);    //畫字符串}public void settishi(Graphics g){               //繪制分數方法Font font1 = new Font(Font.SERIF, Font.BOLD, 25);  //羅馬字體,斜體,40號g.setFont(font1);     //獲取字體g.setColor(Color.black);//獲取顏色g.drawString("點擊屏幕開始運行",110,400);    //畫字符串g.drawString("   制作人---趙嘉盟",120,430);}public void settishi2(Graphics g){               //繪制分數方法Font font2 = new Font(Font.SANS_SERIF, Font.BOLD, 30);  //羅馬字體,斜體,40號g.setFont(font2);     //獲取字體g.setColor(Color.red);//獲取顏色g.drawString("點擊屏幕重新開始",100,500);    //畫字符串}public void action() throws InterruptedException {    //游戲對象運動方法this.addMouseListener(new BirdMouseListener());   //添加鼠標監聽器?    while (true){
?      switch (state){     //狀態不同,對象運動效果不同
?        case START:
?          ground.step();  //調用地面運動方法
?          bird.fly();break;case RUNNING:?          bird.distanceChange();
?          ground.step();  //調用地面運動方法
?          bird.fly();?          if (isHitGround()||isHitSky()){
?            state=GAMEOVER;
?            break;
?          }
?          for (int i=0;i<columns.length;i++){
?            Column cl=columns[i];
?            cl.step();
?            if (isguandao(cl)){
?              state=GAMEOVER;
?              break;
?            }
?            if (bird.x==cl.x){
?              score++;
?            }
?          }?          break;
?        case GAMEOVER:
?          music.stopBGM();
?          break;
?      }
?      repaint();  //刷新方法(重新繪制)
?      Thread.sleep(50);  //線程睡眠
?    }}class BirdMouseListener extends MouseAdapter{      //小鳥飛行鼠標控制監聽內部類
?    @Override
?    public void mousePressed(MouseEvent e) {
?      super.mousePressed(e);?      switch (state){
?        case START:
?          state=RUNNING;  //鼠標點擊開始運行
?          Thread thread = new Thread(music);
?          thread.start();
?          break;
?        case RUNNING:
?          bird.upSpeed(); //鼠標點擊屏幕給小鳥一個初始上拋速度
?          break;
?        case GAMEOVER:
?          sc.insertScore(score);  //向數據庫插入分數
?          List<Score> scores = sc.selectAllScore();//查詢數據庫所有分數
?          String message="";
?          for (Score score1 : scores) {
?            message=message+"時間:"+score1.getTime()+"\n分數:"+score1.getScore()+"\n";
?          }
?          JOptionPane.showConfirmDialog(jp,message,"實時分數",JOptionPane.WARNING_MESSAGE);
?          state=START;   //鼠標點擊游戲恢復開始狀態?          bird.x=120;
?          bird.y=220;
?          bird.speed=0;
?          Column.count=0;
?          try {
?            columns[0] = new Column();
?          } catch (IOException ex) {
?            ex.printStackTrace();
?          }
?          try {
?            columns[1] = new Column();
?          } catch (IOException ex) {
?            ex.printStackTrace();
?          }
?          score = 0;//給積分初始化
?          for (int i=0;i<columns.length;i++){
?            try {
?              columns[i]=new Column();
?            } catch (IOException ex) {
?              ex.printStackTrace();
?            }
?          }?          break;?      }
?    }}
}AI寫代碼java運行

十七、Stream

Stream簡介

Java 8 中的 Stream 是對(Collection)集合對象功能的增強,它專注于對集合對象進行各種非常便利、高效的聚合操作

或大批量數據操作。Stream API 借助于同樣新出現的 Lambda 表達式,極大的提高編程效率和程序可讀性。

Stream原理

這種編程風格將要處理的元素集合看作一種流,流在管道中傳輸,并且可以在管道的節點上進行處理,比如篩選,排序,聚合等。

元素流在管道中經過中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的

結果。

Stream優點

(1)速度更快

(2)代碼更少(增加了新的語法Lambda表達式)

(3)強大的Stream API

(4)便于并行

(5)最大化減少了空指針異常Optional

Stream的操作三個步驟:

(1)創建Stream,一個數據源(如:集合、數組),獲取一個流;

(2)中間操作,一個中間操作鏈,對數據源的數據進行處理;

(3)終止操作,一個終止操作,執行中間操作鏈,并產生結果。

集合有兩種方式生成流:

stream() ? 為集合創建串行流。

parallelStream() ? 為集合創建并行流

-Stream的的中間操作(intermediate)和最終操作(terminal)都包含的方法:


中間操作(intermediate)

1.filter : 通過設置條件來過濾元素。

List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");list.stream().filter((s)->s.contains("a")).forEach(s -> System.out.println(s));AI寫代碼java運行

以上代碼使用filter方法過濾出只包含”a”的元素,然后通過forEach將滿足條件的元素遍歷出來。

map : 就是將對應的元素使用給定方法進行轉換。

List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");list.stream().filter((s)->s.contains("a")).map((s)-> s + "---map").forEach(s -> System.out.println(s));AI寫代碼java運行

在filter的基礎上,給每個元素后面添加字符串”—map”

flatMap:如果流的元素為數組或者Collection,flatMap就是將每個Object[]元素或Collection元素都轉換為Object元素。

List<String[]> setList = new ArrayList<>();setList.add(new String[]{"aa","bb"});setList.add(new String[]{"cc","dd"});setList.add(new String[]{"ee","ff"});//使用map方法setList.stream().map(s->Arrays.stream(s)).forEach(s-> System.out.println("map==" + s));//使用flatMap方法setList.stream().flatMap(s->Arrays.stream(s)).forEach(s-> System.out.println("flatMap==" + s));AI寫代碼java運行

map就是將數組流直接返回,flatMap是將數組流中的每個元素都返回。

.distinct:將集合中的元素去重。

List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");disList.stream().distinct().forEach(s-> System.out.println(s));AI寫代碼java運行

sorted:將集合中的元素排序。

List<Integer> integerList = Arrays.asList(2,4,1,3);integerList.stream().sorted().forEach(s-> System.out.println(s));AI寫代碼java運行

可以按照自定義排序:

List<Integer> integerList = Arrays.asList(2,4,1,3);integerList.stream().sorted((s1,s2)->s2.compareTo(s1)).forEach(s-> System.out.println(s));AI寫代碼java運行

peek:生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函數即引用的方法A,當Stream每個元素被消費的時候都會先
執行新Stream給定的方法A。peek是中間操作,如果peek后沒有最終操作,則peek不會執行。

List<Integer> integerList = Arrays.asList(1,2,3,4);integerList.stream().peek(s-> System.out.println("peek = "+s)).forEach(s-> System.out.println("forEach = "+s));AI寫代碼java運行

limit:返回Stream的前n個元素。

List<Integer> integerList = Arrays.asList(1,2,3,4);integerList.stream().limit(2).forEach(s-> System.out.println(s));AI寫代碼java運行

skip:刪除Stream的前n個元素。

List<Integer> integerList = Arrays.asList(1,2,3,4);integerList.stream().skip(2).forEach(s-> System.out.println(s));AI寫代碼java運行

終端操作(terminal)

1.forEach:遍歷Stream中的每個元素,前面每個例子都有使用,此處不再演示。

List<Integer> integerList = Arrays.asList(1,2,3,4);integerList.stream().skip(2).forEach(s-> System.out.println(s));AI寫代碼java運行

forEachOrdered:遍歷Stream中的每個元素。
區別: 在串行流(stream)中沒有區別,在并行流(parallelStream)中如果數據源是有序集合,forEachOrdered輸出順序與數據源中順序
一致,forEach則是亂序。

List<Integer> integerList = Arrays.asList(1,2,3,4);integerList.parallelStream().forEachOrdered(s-> System.out.println(s));AI寫代碼java運行

toArray:將流轉換為Object[]或者指定類型的數組。

List<Integer> integerList = Arrays.asList(1,2,3,4);Object[] array = integerList.stream().toArray();String[] strArr = integerList.stream().toArray(String[]::new);AI寫代碼java運行

Stream中的toArray普通情況下和集合中的toArray沒什么區別,但是Stream中的toArray轉換為指定類型的數組。

reduce:將集合中的每個元素聚合成一條數據。有三種情況:

reduce(BinaryOperator accumulator):此處需要一個參數,返回Optional對象:

Optional reduce = integerList.stream().reduce((a, b) -> a + b);

reduce(T identity, BinaryOperator accumulator):此處需要兩個參數,第一個參數為起始值,第二個參數為引用的方法

從起始值開始,每個元素執行一次引用的方法(方法引用的中的兩個參數:第一個參數為上個元素執行方法引用的結果,第二個參數為當前元素)。

    List<Integer> integerList = Arrays.asList(1,2,3,4);int integer = integerList.stream().reduce(5,(a, b) -> a + b);System.out.println(integer);AI寫代碼java運行

此例中使用起始值為5,對集合中每個元素求和,可以理解為:5+1+2+3+4=15。

**reduce:**此處需要三個參數。此方法用在并發流(parallelStream)中,啟動多個子線程使用accumulator進行并行計算,最終使用combiner對子線程結果進行合并,返回identity類型的數據。

collect:將流轉換成集合或聚合元素。有兩種情況。接受一個參數和接受三個參數(三個參數在并發流parallelStream中使用),此處介紹一個參數的情況,單個參數接受的參數類型為Collector,Collectors 類實現了很多歸約操作

List<Integer> integerList = Arrays.asList(2,4,1,3);List<Integer> integers = integerList.stream().filter(s -> s > 1).collect(Collectors.toList());System.out.println(integers.toString());AI寫代碼java運行

此處統計集合中大于1的元素并最終返回list。

min:獲取集合中最小值。

List<Integer> integerList = Arrays.asList(2,4,1,3);Integer min = integerList.stream().min(Integer::compareTo).get();System.out.println(min);AI寫代碼java運行

max:獲取集合中最大值。

List<Integer> integerList = Arrays.asList(2,4,1,3);Integer max = integerList.stream().max(Integer::compareTo).get();System.out.println(max);AI寫代碼java運行

count:獲取集合中元素個數

List<Integer> integerList = Arrays.asList(2,4,1,3);long count = integerList.stream().count();System.out.println(count);AI寫代碼java運行

原文地址:https://blog.csdn.net/m0_57376564/article/details/148143797

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

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

相關文章

火山引擎發布大模型生態廣場MCP Servers,LAS MCP助力AI數據湖構建

資料來源&#xff1a;火山引擎-開發者社區 近日&#xff0c;火山引擎發布大模型生態廣場—— MCP Servers&#xff0c;借助字節跳動生態能力&#xff0c;通過“MCP Market&#xff08;工具廣場&#xff09; 火山方舟&#xff08;大模型服務&#xff09;Trae&#xff08;應用開…

NodeJS 對接 Outlook 發信服務器實現發信功能

示例代碼&#xff1a; const express require(express); const nodemailer require(nodemailer); const querystring require(querystring); const axios require(axios);const app express(); app.use(express.json());const transporter nodemailer.createTransport({…

【同聲傳譯】RealtimeSTT:超低延遲語音轉文字,支持喚醒詞與中譯英

把你說的話實時變成文字&#xff1a;RealtimeSTT 上手體驗 想找一個真正好用的語音轉文字工具嗎&#xff1f;不用等說完一整段才出結果&#xff0c;也不用反復點擊按鈕。RealtimeSTT 這個開源項目能做到??實時??轉錄&#xff0c;你說一句&#xff0c;屏幕上幾乎同時出現文…

【大模型lora微調】關于推理時如何使用 LoRA Adapter

假設你有兩部分&#xff1a; 一個是原始大模型&#xff08;base model&#xff09; 一個是保存的 LoRA Adapter&#xff08;adapter_config.json adapter_model.bin&#xff09; 不合并的情況下推理方法 你可以用 peft 的方式加載 LoRA Adapter&#xff0c;推理時這樣寫&a…

谷歌時間序列算法:零樣本預測如何重塑行業決策?

谷歌時間序列算法&#xff1a;零樣本預測如何重塑行業決策&#xff1f; TimesFM 你是否曾面臨這樣的困境&#xff1f;—— ? 需要預測新產品銷量&#xff0c;卻苦于缺乏歷史數據&#xff1b; ? 依賴傳統模型&#xff08;如ARIMA&#xff09;&#xff0c;但調參耗時且泛化能力…

國產服務器【銀河麒麟v10】【CPU鯤鵬920】部署Minio文件服務器

目錄 準備工作操作步驟1. 確認掛載點狀態2. 創建專用用戶和目錄3. 下載ARM版Minio到掛在盤4. 環境變量配置5. 更新Systemd服務配置6. 啟動、重啟7. 防火墻8. 訪問驗證9. 故障排查&#xff08;如服務未啟動&#xff09;? 結束 準備工作 環境要求&#xff1a;Linux虛擬機 操作…

解決: React Native android webview 空白頁

Android react-native-webview 之前是正常的, 升級了 react-native / react-native-webview 等 之后, 就變成了空白頁. 通過下面的修改, 可以修復, 回到正常的狀態. 來源: https://github.com/react-native-webview/react-native-webview/issues/3697 注意 ts 文件一定要改,…

高中編程教學中教師專業發展的困境與突破:基于實踐與理論的雙重審視

一、引言 1.1 研究背景 在數字化時代&#xff0c;編程已成為一項基本技能&#xff0c;其重要性日益凸顯。編程不僅是計算機科學領域的核心能力&#xff0c;更是培養學生邏輯思維、創新能力和問題解決能力的有效途徑。高中階段作為學生成長和發展的關鍵時期&#xff0c;開展編…

最小化聯邦平均(FedAvg)的算法開銷

一、通信開銷最小化 FedAvg中服務器與客戶端間的頻繁參數傳輸是主要瓶頸&#xff0c;可通過以下方法優化&#xff1a; 1. 模型壓縮技術 稀疏化&#xff1a;僅上傳重要參數更新&#xff08;如Top-k梯度&#xff09; 實現&#xff1a;客戶端本地訓練后&#xff0c;保留絕對值最…

準備開始適配高德Flutter的鴻蒙版了

我們的Flutter項目在編譯為鴻蒙的過程中&#xff0c; 遇到了各種插件不支持的問題。 大部分都能解決&#xff0c;或者用別的方式代替。 這個高德我真的是無語&#xff0c; 我們只能用高德 &#xff0c; 目前還沒看到網上有人適配了鴻蒙。 那就我來干吧&#xff0c; 第一…

webpack到vite的改造之路

前言 隨著前端項目的持續迭代與功能擴展&#xff0c;當前基于 Webpack 構建的項目在啟動速度、構建速度和首屏加載性能方面逐漸暴露出一些瓶頸。 一方面&#xff0c;Webpack 的打包機制導致本地開發環境的啟動時間顯著增加&#xff0c;嚴重影響了開發效率&#xff1b;另一方面…

【重構】如果發現提取的方法不再通用,如何重構

前言 所謂重構&#xff08;refactoring&#xff09;&#xff1a; 在不改變代碼外在行為的前提下&#xff0c;對代碼做出修改&#xff0c;以改進程序的內部結構。 – Martin Fowler背景 最近在做需求&#xff0c;需要對方法加權限控制&#xff0c;發現舊方法不再適用&#xff0…

REST接口/RPC

REST接口(RESTful API)是一種基于HTTP協議的API設計風格,遵循REST(Representational State Transfer表述性狀態轉移)架構原則,用于在不同系統之間進行數據交互。它具有簡潔、靈活、無狀態等特點,廣泛應用于Web服務和移動應用開發中。 核心概念 資源導向 將數據或服務抽…

JS入門——事件與事件綁定

JS入門——事件與事件綁定 一、事件的分類 二、事件的綁定方式 實現代碼&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>JS事件綁定</title></head><body><!-- 修復后的按鈕1 -->&…

pyspark 處理字符串函數

pyspark 要處理數據&#xff0c;沒有&#xff0c;那就偽造數據 faker 真是個好東西 from faker import Faker import pandas as pd gender ["None","Man","Woman"]fake Faker() names [(fake.first_name(),fake.last_name(),fake.date_of_bi…

五大經典語音芯片型號及應用場景

在語音芯片領域&#xff0c;這五大語音芯片憑借豐富多樣的產品和卓越的性能&#xff0c;占據了重要地位。以下為您詳細介紹其五款經典語音芯片型號及其對應的應用場景。? WTN6170-8S? WTN6170-8S 屬于 OTP 一次性語音芯片。它采用 OTP 工藝&#xff0c;成本能夠控制在 1 元以…

機器學習管道:構建高效可靠的AI工作流

在當今數據驅動的世界中&#xff0c;機器學習(ML)已成為推動創新和決策的核心技術。然而&#xff0c;將ML模型從實驗環境成功部署到生產環境并非易事。機器學習管道(ML Pipelines)作為一種系統化的解決方案&#xff0c;通過自動化工作流程&#xff0c;顯著提高了ML項目的可重復…

瀏覽器調試核心技術指南:從基礎到高級的完全掌握

引言?? 在現代前端開發中,瀏覽器調試工具已成為開發者最強大的技術伙伴。根據State of JS 2023的統計數據,??92.7%的專業開發者??每天使用瀏覽器DevTools進行問題診斷和性能優化。然而,多數初級開發者僅能使用不到35%的調試功能。本文將系統解析Chrome/Firefox瀏覽器…

OpenCV 圖像翻轉

一、知識點 1、void flip(InputArray src, OutputArray dst, int flipCode); (1)、圍繞x軸、y軸或兩者同時翻轉圖像。 (2)、參數說明: src: 輸入圖像。 dst: 輸出圖像&#xff0c;大小與類型和src相同。 flipCode: 翻轉標志。 0表示繞x軸翻轉(上下翻轉);…

【動手學深度學習】4.2~4.3 多層感知機的實現

目錄 4.2. 多層感知機的從零開始實現1&#xff09;初始化模型參數2&#xff09;激活函數3&#xff09;模型4&#xff09;損失函數5&#xff09;訓練 4.3. 多層感知機的簡潔實現1&#xff09;模型2&#xff09;小結 . 4.2. 多層感知機的從零開始實現 現在讓我們實現一個多層感…