Java 基礎學習第一彈

来源:https://www.cnblogs.com/beyond-tester/archive/2023/10/29/17796185.html
-Advertisement-
Play Games

1. equels和==的區別 equals方法用於比較對象的內容是否相等,可以根據自定義的邏輯來定義相等的條件,而==操作符用於比較對象的引用是否相等,即它們是否指向同一塊記憶體地址。equals方法是一個 實例方法,可以被所有的Java對象調用,而==操作符可以用於比較對象的引用或基本數據類型的值 ...


1. equels和==的區別

  equals方法用於比較對象的內容是否相等,可以根據自定義的邏輯來定義相等的條件,而==操作符用於比較對象的引用是否相等,即它們是否指向同一塊記憶體地址。equals方法是一個

實例方法,可以被所有的Java對象調用,而==操作符可以用於比較對象的引用或基本數據類型的值。equals方法的行為可以被重寫,以適應特定的比較需求,而==操作符的行為不可修改。

2. 垃圾回收機制

  垃圾回收是一種在堆記憶體中找出哪些對象在被使用,還有哪些對象沒被使用,並且將後者回收掉的機制。所謂使用中的對象,指的是程式中還有引用的對象;而未使用中的對象,指的是程

序中已經沒有引用的對象,該對象占用的記憶體也可以被回收掉。垃圾回收的第一步是標記。垃圾回收器此時會找出記憶體哪些在使用中,哪些不是。垃圾回收的第二步是清除,這一步會刪掉標記

出的未引用對象。記憶體分配器會保留指向可用記憶體中的引用,以分配給新的對象。垃圾回收的第三步是壓縮,為了提升性能,刪除了未引用對象後,還可以將剩下的已引用對象放在一起(壓  

縮),這樣就能更簡單快捷地分配新對象了。逐一標記和壓縮  Java 虛擬機中的所有對象非常低效:分配的對象越多,垃圾回收需要的時間就越久。不過,根據統計,大部分的對象,其實用沒

多久就不用了。

Java 堆(Java Heap)是 JVM 所管理的記憶體中最大的一塊,堆又是垃圾收集器管理的主要區域,這裡我們主要分析一下 Java 堆的結構。

Java 堆主要分為 2 個區域-年輕代與老年代,其中年輕代又分 Eden 區和 Survivor 區,其中 Survivor 區又分 From 和 To 2 個區。可能這時候大家會有疑問,為什麼需要 Survivor 區,為什麼 Survivor 還要分 2 個區。

大多數情況下,對象會在新生代 Eden 區中進行分配。當 Eden 區沒有足夠空間進行分配時,虛擬機會發起一次 Minor GC,Minor GC 相比 Major GC 更頻繁,回收速度也更快。

通過 Minor GC 之後,Eden 會被清空,Eden 區中絕大部分對象會被回收,而那些無需回收的存活對象,將會進到 Survivor 的 From 區(若 From 區不夠,則直接進入 Old 區)。

Survivor 區相當於是 Eden 區和 Old 區的一個緩衝,類似於我們交通燈中的黃燈。Survivor 又分為 2 個區,一個是 From 區,一個是 To 區。每次執行 Minor GC,會將 Eden 區和 From 存活的對象放到 Survivor 的 To 區(如果 To 區不夠,則直接進入 Old 區)。

之所以有 Survivor 區是因為如果沒有 Survivor 區,Eden 區每進行一次 Minor GC,存活的對象就會被送到老年代,老年代很快就會被填滿。而有很多對象雖然一次 Minor GC 沒有消滅,但其實也並不會蹦躂多久,或許第二次,第三次就需要被清除。這時候移入老年區,很明顯不是一個明智的決定。

所以,Survivor 的存在意義就是減少被送到老年代的對象,進而減少 Major GC 的發生。Survivor 的預篩選保證,只有經歷 16 次 Minor GC 還能在新生代中存活的對象,才會被送到老年代。

設置兩個 Survivor 區最大的好處就是解決記憶體碎片化。

我們先假設一下,Survivor 如果只有一個區域會怎樣。Minor GC 執行後,Eden 區被清空了,存活的對象放到了 Survivor 區,而之前 Survivor 區中的對象,可能也有一些是需要被清除的。問題來了,這時候我們怎麼清除它們?在這種場景下,我們只能標記清除,而我們知道標記清除最大的問題就是記憶體碎片,在新生代這種經常會消亡的區域,採用標記清除必然會讓記憶體產生嚴重的碎片化。因為 Survivor 有 2 個區域,所以每次 Minor GC,會將之前 Eden 區和 From 區中的存活對象複製到 To 區域。第二次 Minor GC 時,From 與 To 職責互換,這時候會將 Eden 區和 To 區中的存活對象再複製到 From 區域,以此反覆。

這種機制最大的好處就是,整個過程中,永遠有一個 Survivor space 是空的,另一個非空的 Survivor space 是無碎片的。那麼,Survivor 為什麼不分更多塊呢?比方說分成三個、四個、五個?顯然,如果 Survivor 區再細分下去,每一塊的空間就會比較小,容易導致 Survivor 區滿,兩塊 Survivor 區可能是經過權衡之後的最佳方案。

老年代占據著 2/3 的堆記憶體空間,只有在 Major GC 的時候才會進行清理,每次 GC 都會觸發“Stop-The-World”。記憶體越大,STW 的時間也越長,所以記憶體也不僅僅是越大就越好。在記憶體擔保機制下,無法安置的對象會直接進到老年代,以下幾種情況也會進入老年代。

1)大對象,指需要大量連續記憶體空間的對象,這部分對象不管是不是“朝生夕死”,都會直接進到老年代。這樣做主要是為了避免在 Eden 區及 2 個 Survivor 區之間發生大量的記憶體複製。

2)長期存活對象,虛擬機給每個對象定義了一個對象年齡(Age)計數器。正常情況下對象會不斷的在 Survivor 的 From 區與 To 區之間移動,對象在 Survivor 區中每經歷一次 Minor GC,年齡就增加 1 歲。當年齡增加到 15 歲時,這時候就會被轉移到老年代。當然,這裡的 15,JVM 也支持進行特殊設置。

3)動態對象年齡,虛擬機並不重視要求對象年齡必須到 15 歲,才會放入老年區,如果 Survivor 空間中相同年齡所有對象大小的總合大於 Survivor 空間的一半,年齡大於等於該年齡的對象就可以直接進去老年區,無需等你“成年”。

這其實有點類似於負載均衡,輪詢是負載均衡的一種,保證每台機器都分得同樣的請求。看似很均衡,但每台機的硬體不通,健康狀況不同,我們還可以基於每台機接受的請求數,或每台機的響應時間等,來調整我們的負載均衡演算法。

3. String、StringBuffer、StringBuilder的區別

在Java中,StringStringBufferStringBuilder都是用於處理字元串的類,但它們在性能、線程安全性和可變性方面存在一些區別。

String(字元串)String是Java中最常用的字元串類,它是不可變的(immutable)。這意味著一旦創建了一個String對象,它的值就不能被修改。每次對String的操作(例如連接、替換等)都會創建一個新的String對象。這種不可變性使得String具有線程安全性,適合在多線程環境下使用。然而,頻繁的字元串操作可能會導致記憶體開銷較大,因為每次操作都會創建新的對象。

String str = "Hello";
str += " World"; // 創建了一個新的String對象
```

StringBuffer(字元串緩衝區)StringBuffer是可變的(mutable)字元串類,它可以進行多次修改而無需創建新的對象。StringBuffer是線程安全的,適用於多線程環境下的字元串操作。它提供了多個方法用於對字元串進行修改、連接、插入和刪除等操作。

StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 在原對象上進行修改,無需創建新對象
```

由於`StringBuffer`是線程安全的,它的執行速度相對較慢。因此,如果在單線程環境下進行字元串操作,推薦使用`StringBuilder`,因為它的執行速度更快。

StringBuilder(字元串構建器)StringBuilder也是可變的字元串類,類似於StringBuffer,它可以進行多次修改而無需創建新的對象。StringBuilder不是線程安全的,因此在多線程環境下使用時需要進行外部同步。由於不需要額外的線程安全檢查,StringBuilder的執行速度相對較快。

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 在原對象上進行修改,無需創建新對象
```

總結:

  • 如果需要頻繁操作字元串,並且在多線程環境下使用,應該使用StringBuffer
  • 如果需要頻繁操作字元串,但在單線程環境下使用,應該使用StringBuilder,因為它的執行速度更快。
  • 如果不需要頻繁操作字元串,或者字元串是不可變的,可以使用String

4. 操作字元串常見的類及方法

String類:String是Java中最常用的字元串類,它提供了許多方法來處理字元串。以下是一些示例:

String str1 = "Hello";
String str2 = "World";

// 連接字元串
String result1 = str1 + str2; // 結果為 "HelloWorld"

// 獲取字元串長度
int length = str1.length(); // 結果為 5

// 檢查字元串是否為空
boolean isEmpty = str1.isEmpty(); // 結果為 false

// 檢查字元串是否包含指定字元
boolean contains = str1.contains("H"); // 結果為 true

// 提取子字元串
String subStr = str1.substring(1, 4); // 結果為 "ell"

// 替換字元
String replacedStr = str1.replace("H", "J"); // 結果為 "Jello"

// 拆分字元串
String[] parts = str1.split("l"); // 結果為 ["He", "", "o"]

// 轉換為大寫或小寫
String upperCase = str1.toUpperCase(); // 結果為 "HELLO"
String lowerCase = str1.toLowerCase(); // 結果為 "hello"

StringBuilder類:StringBuilder用於構建可變字元串,它提供了一系列方法來進行字元串的拼接和修改。以下是一些示例:

StringBuilder sb = new StringBuilder();

// 追加字元串
sb.append("Hello");
sb.append("World");

// 插入字元串
sb.insert(5, " ");

// 替換字元串
sb.replace(6, 11, "Java");

// 刪除字元
sb.deleteCharAt(5);

// 反轉字元串
sb.reverse();

String result2 = sb.toString(); // 結果為 "avaJdlroW"

StringBuffer類:StringBufferStringBuilder類似,也用於構建可變字元串。不同的是,StringBuffer是線程安全的,適用於多線程環境下的字元串操作。以下是一個示例:

StringBuffer buffer = new StringBuffer();

buffer.append("Hello");
buffer.append("World");

String result3 = buffer.toString(); // 結果為 "HelloWorld"

5. Static的用法和作用

static 是Java中的一個關鍵字,可以應用於變數、方法和代碼塊。它具有以下幾種用法和作用:

靜態變數(Static Variables):使用 static 關鍵字聲明的變數稱為靜態變數,也稱為類變數。靜態變數屬於類而不是實例,它在類載入時被初始化,並且在整個程式執行期間保持不變。靜態變數可以通過類名直接訪問,無需創建類的實例。靜態變數常用於表示在類的所有實例之間共用的數據。

public class MyClass {
    static int count = 0; // 靜態變數

    public MyClass() {
        count++; // 每次創建實例時,靜態變數 count 自增
    }
}

靜態方法(Static Methods):使用 static 關鍵字聲明的方法稱為靜態方法。靜態方法屬於類而不是實例,它可以在類載入時直接調用,無需創建類的實例。靜態方法只能訪問靜態變數和調用其他靜態方法,不能直接訪問實例變數或調用實例方法。

public class MathUtils {
    public static int add(int a, int b) { // 靜態方法
        return a + b;
    }
}

靜態代碼塊(Static Initialization Blocks):靜態代碼塊用於在類載入時執行一些初始化操作。它使用 static 關鍵字定義,並用花括弧括起來的代碼塊。靜態代碼塊只執行一次,且在類的第一次使用時執行。

public class MyClass {
    static {
        // 靜態代碼塊
        // 執行一些初始化操作
    }
}

靜態代碼塊通常用於初始化靜態變數或執行其他與類相關的初始化操作。

靜態導入(Static Import):靜態導入用於在代碼中直接使用靜態成員(變數或方法),而無需使用類名限定符。通過使用 import static 語法,可以導入靜態成員,使其在代碼中可直接訪問。

import static java.lang.Math.PI;

public class MyClass {
    public double calculateArea(double radius) {
        return PI * radius * radius; // 直接使用靜態變數 PI,無需使用 Math.PI
    }
}

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. Gremlin Server只將數據存儲在記憶體中 1.1. 如果停止Gremlin Server,將丟失資料庫里的所有數據 2. 概念 2.1. 遍歷(動詞) 2.1.1. 當在圖資料庫中導航時,從頂點到邊或從邊到頂點的移動過程 2.1.2. 類似於在關係資料庫中的查詢行為 2.2. 遍歷(名 ...
  • 作者:盧文雙 資深資料庫內核研發 本文首發於 2023-05-04 22:07:40 http://dbkernel.com/2023/05/04/mysql-threadpool-main-solutions-details/# 本文主要從功能層面對比 percona-server、mariadb ...
  • 因為工作的原因又回到了vue的領域,需要加深對vue和vue生態的瞭解也許平時比較多人手機看別人解析怎麼看vue源碼的,自己動手看vue源碼的還是比較少,這次我想自己動手看看首先 吧代碼獲取到本地跑起來vue 倉庫地址 https://github.com/vuejs/vue 開發環境 搭建指南 h ...
  • 代碼塊 寫法: {} 使用代碼塊,可以對代碼進行分組,同一個代碼塊中的代碼就是同一組代碼,一個代碼塊中的代碼,要麼都執行,要麼都不執行 let 和 var的區別 在JS中,let聲明的變數具有塊級作用域 var聲明的變數,不具有塊級作用域 var聲明的變數會將變數的聲明提至最前 對象 原始值只能表示 ...
  • 在前端編程中,處理一些簡短、快速的操作,在主線程中就可以完成。 但是,在處理一些耗時比較長以至於比較明顯的事情,比如讀取一個大文件或者發出一個網路請求,就需要非同步編程來實現,以避免只用主線程時造成頁面一時無法響應的事情。 以發送網路請求為例,在以往的JavaScript中,使用多個回調函數來處理請求 ...
  • 本文主要介紹了筆者的一次flask後端開發的項目實踐中的功能實現,包括文件讀寫、數據讀取、遠程ssh連接、命令行執行、多線程操作等。 ...
  • Python 中的日期不是獨立的數據類型,但我們可以導入一個名為 datetime 的模塊來使用日期作為日期對象。 示例:導入 datetime 模塊並顯示當前日期: import datetime x = datetime.datetime.now() print(x) 日期輸出 當我們執行上面示 ...
  • 前面一些文章,老周簡單介紹了在Qt 中使用列表模型的方法。很明顯,使用 Item Model 在許多時候還是挺麻煩的——要先建模型,再放數據,最後才構建視圖。為了簡化這些騷操作,Qt 提供了幾個便捷類。今天咱們逐個看看。 一、QListWidget 這廝對應的 List View,用來顯示簡單的列表 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...