總結的Java知識點集合

来源:https://www.cnblogs.com/HanXuxian/p/18051640
-Advertisement-
Play Games

這是我讀大學時的Java知識點總結,還不全面,後續會逐漸增加完善。 知識點集合 實例變數 實例變數是指在類中聲明的變數,其值是針對類的每個實例而獨立存儲的。每個類的實例都有自己的一組實例變數,它們的值可以在對象創建時初始化,併在整個對象的生命周期中保持不變或者隨著對象的狀態而改變。 實例變數也被稱為 ...


這是我讀大學時的Java知識點總結,還不全面,後續會逐漸增加完善。

知識點集合

實例變數

實例變數是指在類中聲明的變數,其值是針對類的每個實例而獨立存儲的。每個類的實例都有自己的一組實例變數,它們的值可以在對象創建時初始化,併在整個對象的生命周期中保持不變或者隨著對象的狀態而改變。

實例變數也被稱為對象變數,因為它們是在類的對象實例化時創建的,並且每個對象都有自己的一組實例變數。

實例變數的特點包括:

  • 它們屬於對象,而不是類本身。
  • 每個對象都有自己的一組實例變數,每個對象的實例變數值可以是不同的。
  • 它們在對象的整個生命周期中存在,並且可以被對象的方法訪問和修改。
  • 實例變數不能使用 static 關鍵字進行修飾,而是通過實例化對象來訪問。

以下是一個示例,演示瞭如何在Java中定義和使用實例變數:

public class Person {
    // 實例變數
    String name;
    int age;
    
    public void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}

// 創建對象並設置實例變數的值
Person person = new Person();
person.name = "John";
person.age = 25;

// 調用方法訪問和使用實例變數
person.displayInfo();

在這個例子中,Person 類有兩個實例變數 nameage,它們屬於每個 Person 對象的一部分。在創建 Person 對象後,可以通過訪問對象的實例變數來設置和獲取它們的值。在 displayInfo() 方法中,可以使用實例變數來展示對象的信息。

因此,實例變數是定義在類中的變數,每個對象都有自己獨立的一組實例變數,用於存儲對象的狀態和屬性。

實例化對象

實例化對象是根據類的定義創建一個具體的對象,也可以說是將類實例化為對象的過程。

在面向對象編程中,類是對象的模板,描述了對象應該具有的屬性和行為。通過實例化對象,我們可以根據類的定義創建一個具體的實體,該實體具有類中定義的屬性和行為。

在Java中,通過使用 new 關鍵字和類的構造方法來實例化對象。構造方法是一種特殊的方法,用於創建對象並初始化其屬性。

以下是一個示例:

// 定義一個類
class Person {
    private String name;
    private int age;
    
    // 構造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 方法
    public void sayHello() {
        System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
    }
}

public class Main {
    public static void main(String[] args) {
        // 實例化對象
        Person person = new Person("John", 25);
        
        // 調用對象的方法
        person.sayHello(); // 輸出 "Hello, my name is John and I'm 25 years old."
    }
}

在上面的示例中,我們定義了一個 Person 類,具有 nameage 屬性,以及 sayHello() 方法。通過 new 關鍵字和 Person 類的構造方法,我們實例化了一個 Person 對象,並將其賦值給 person 變數。

通過 person 對象,我們可以調用 sayHello() 方法,該方法會輸出對象的屬性值。

實例化對象是面向對象編程的基本概念之一,它允許我們創建具體的對象實例,並根據類定義的屬性和行為進行操作。

抽象類

Java 中的抽象類是不能被實例化的,只能被繼承。抽象類是用來作為其他類的父類或基類,它本身不能被實例化為對象。

抽象類是通過在類定義中使用關鍵字 abstract 來標識的。抽象類可以包含抽象方法,這些方法沒有具體的實現,需要在子類中進行重寫實現。抽象類可以有普通方法和成員變數,可以提供一些共用的實現邏輯給子類使用。

以下是一個示例:

// 抽象類
abstract class Animal {
    // 抽象方法
    public abstract void makeSound();
    
    // 普通方法
    public void sleep() {
        System.out.println("Animal is sleeping");
    }
}

// 繼承抽象類
class Cat extends Animal {
    // 實現抽象方法
    public void makeSound() {
        System.out.println("Meow");
    }
}

public class Main {
    public static void main(String[] args) {
        // 錯誤示例,不能實例化抽象類
        // Animal animal = new Animal();
        
        // 創建子類對象
        Animal cat = new Cat();
        cat.makeSound(); // 輸出 "Meow"
        cat.sleep(); // 輸出 "Animal is sleeping"
    }
}

在上面的示例中,Animal 類是一個抽象類,其中包含了一個抽象方法 makeSound() 和一個普通方法 sleep()。不能直接實例化 Animal 類,但可以通過繼承它的子類 Cat 來創建對象。

多態性

Java 中的多態性(polymorphism)是指在一個類層次結構中,子類可以以自己的形式重寫父類的方法,並且可以使用父類的引用來引用子類的對象。這種特性允許我們通過父類的引用來調用子類特定的方法,從而實現不同類型的對象以相同的方式進行操作。

多態性是面向對象編程的重要特性之一,它提高了代碼的靈活性和可擴展性。通過多態性,我們可以編寫通用的代碼,而不需要針對每個具體的子類編寫獨立的代碼。

以下是一個示例:

// 父類
class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

// 子類1
class Dog extends Animal {
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

// 子類2
class Cat extends Animal {
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog(); // 子類對象賦值給父類引用
        Animal animal2 = new Cat(); // 子類對象賦值給父類引用
        
        animal1.makeSound(); // 調用子類的方法,輸出 "Dog barks"
        animal2.makeSound(); // 調用子類的方法,輸出 "Cat meows"
    }
}

在上面的示例中,我們定義了一個 Animal 父類和兩個子類 DogCat。通過將子類對象賦值給父類引用,我們可以使用父類的引用來調用子類的方法。在 main 方法中,我們創建了一個 Dog 對象,並將其賦值給 Animal 類型的引用 animal1,以及創建了一個 Cat 對象,並將其賦值給 Animal 類型的引用 animal2。然後,我們通過這兩個引用調用了 makeSound() 方法,分別輸出了相應的子類特定的聲音。

子類不能覆蓋父類的私有(private)方法

在 Java 中,子類不能覆蓋父類的私有(private)方法。私有方法是指只能在聲明它的類內部訪問的方法,無法被其他類或子類所訪問。

子類繼承父類的方法有以下幾種情況:

  1. 如果父類的方法是公共(public)或受保護(protected)的,子類可以重寫(覆蓋)該方法。
  2. 如果父類的方法是預設訪問修飾符(即沒有修飾符)的,子類可以重寫該方法,前提是子類與父類在同一個包中。
  3. 如果父類的方法是私有的,子類無法訪問該方法,因此也無法重寫它。

以下是一個示例:

class Parent {
    public void publicMethod() {
        System.out.println("Parent's public method");
    }
    
    protected void protectedMethod() {
        System.out.println("Parent's protected method");
    }
    
    private void privateMethod() {
        System.out.println("Parent's private method");
    }
}

class Child extends Parent {
    // 重寫父類的公共方法
    public void publicMethod() {
        System.out.println("Child's public method");
    }
    
    // 重寫父類的受保護方法
    protected void protectedMethod() {
        System.out.println("Child's protected method");
    }
    
    // 無法重寫父類的私有方法,編譯報錯
    // private void privateMethod() {
    //     System.out.println("Child's private method");
    // }
}

public class Main {
    public static void main(String[] args) {
        Parent parent = new Parent();
        parent.publicMethod(); // 輸出 "Parent's public method"
        parent.protectedMethod(); // 輸出 "Parent's protected method"
        // parent.privateMethod(); // 編譯報錯,私有方法無法訪問
        
        Child child = new Child();
        child.publicMethod(); // 輸出 "Child's public method"
        child.protectedMethod(); // 輸出 "Child's protected method"
    }
}

在上面的示例中,我們定義了一個 Parent 父類和一個 Child 子類。父類中有三個方法,分別是公共方法、受保護方法和私有方法。子類繼承了父類,並重寫了父類的公共方法和受保護方法。然而,子類無法重寫父類的私有方法,因為私有方法只能在父類內部訪問。

Runnable 介面並實現 run() 方法

Runnable 是一個介面,其中定義了一個抽象方法 run(),該方法包含線程的執行邏輯。實現了 Runnable 介面的類需要實現 run() 方法,併在該方法中編寫線程的具體執行邏輯。

創建線程的步驟如下:

  1. 創建一個類,實現 Runnable 介面。例如:
public class MyRunnable implements Runnable {
    public void run() {
        // 線程的執行邏輯
        System.out.println("Thread is running.");
    }
}
  1. 在實現了 Runnable 介面的類中,編寫線程的具體執行邏輯,即在 run() 方法中定義線程的行為。
  2. 在主線程或其他線程中,創建 Thread 對象,並將實現了 Runnable 介面的類的實例作為參數傳遞給 Thread 的構造函數。例如:
public class Main {
    public static void main(String[] args) {
        // 創建實現了 Runnable 介面的類的實例
        MyRunnable myRunnable = new MyRunnable();

        // 創建 Thread 對象,並將實現了 Runnable 介面的類的實例作為參數傳遞
        Thread thread = new Thread(myRunnable);

        // 啟動線程
        thread.start();
    }
}

通過將實現了 Runnable 介面的類的實例傳遞給 Thread 的構造函數,可以創建一個新的線程,併在該線程中執行實現了 run() 方法的代碼邏輯。

這種方式的優勢是可以實現多重繼承,因為 Java 不支持多重繼承,但可以實現多個介面。同時,它也更加靈活,因為同一個 Runnable 對象可以被多個線程共用,從而實現線程的資源共用。

總之,通過實現 Runnable 介面並實現 run() 方法,可以創建一個新的類作為線程的執行體,併在創建線程時將該類的實例傳遞給 Thread 對象來創建新線程。

先進後出(LIFO)

先進後出(Last-In-First-Out,LIFO)是一種數據結構,其中最後插入的元素首先被訪問或刪除。以下是實現先進後出的一些常見數據結構:

  1. 堆棧(Stack):堆棧是一種基於 LIFO 原則的數據結構,它使用 push() 方法將元素添加到棧的頂部,並使用 pop() 方法從棧的頂部刪除和訪問元素。
  2. 遞歸調用:在編程中,遞歸調用也可以看作是一種先進後出的行為。每次進行遞歸調用時,當前的函數調用被暫停並推入調用棧,直到遞歸結束開始逐個彈出並執行。

需要註意的是,先進後出是與先進先出(FIFO)相對的概念。在先進後出的數據結構中,最後插入的元素首先被訪問或刪除;而在先進先出的數據結構中,最先插入的元素首先被訪問或刪除。

先進先出(FIFO)

JAVA異常

在 Java 中,異常分為兩種類型:編譯時異常(Checked Exception)和運行時異常(Runtime Exception)。
編譯時異常(Checked Exception)是在編譯階段檢測到的異常,需要在代碼中進行處理或聲明拋出。它們通常表示程式在運行過程中可能出現的外部因素引起的錯誤或異常情況。IOException 是編譯時異常的一個常見例子,表示輸入輸出操作可能出現的錯誤,例如文件不存在或讀寫錯誤等。
運行時異常(Runtime Exception)是在程式運行時發生的異常,不需要在代碼中進行強制處理或聲明拋出。它們通常表示程式邏輯錯誤或編程錯誤,例如除以零、數組越界等。RuntimeException 是運行時異常的一個常見例子。

靜態方法

靜態方法是在類級別上定義的方法,與特定的對象實例無關。它屬於類本身,而不是類的實例。可以通過類名直接調用靜態方法,而無需創建類的對象。

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

    public static void staticMethod() {
        System.out.println("這是一個靜態方法");
    }

    public void instanceMethod() {
        System.out.println("這是一個實例方法");
    }

    public static int getCount() {
        return count;
    }

    public static void setCount(int value) {
        count = value;
    }
}

在上面的代碼中,我們定義了一個名為MyClass的類。其中包含一個靜態方法staticMethod()和一個實例方法instanceMethod()。還有一個靜態變數count,並提供了靜態的getter和setter方法。

可以通過以下方式調用靜態方法和訪問靜態變數:

MyClass.staticMethod(); // 調用靜態方法

MyClass myObject = new MyClass();
myObject.instanceMethod(); // 調用實例方法

int currentCount = MyClass.getCount(); // 獲取靜態變數的值
MyClass.setCount(10); // 設置靜態變數的值

請註意,靜態方法可以直接通過類名調用,而實例方法需要通過類的對象調用。靜態方法可以在沒有類的實例的情況下使用,因為它們屬於類本身。而實例方法需要通過類的對象來調用,因為它們與特定的對象實例相關聯。

靜態變數

public class StaticVariableExample {
    // 靜態變數
    static int staticVariable = 10;
    // 實例變數
    int instanceVariable = 20;

    public static void main(String[] args) {
        // 直接通過類名訪問靜態變數
        System.out.println("靜態變數的值:" + StaticVariableExample.staticVariable);

        // 創建類的實例對象
        StaticVariableExample obj = new StaticVariableExample();
        // 通過實例對象訪問實例變數
        System.out.println("實例變數的值:" + obj.instanceVariable);

        // 修改靜態變數的值
        StaticVariableExample.staticVariable = 30;
        // 修改實例變數的值
        obj.instanceVariable = 40;

        // 再次訪問靜態變數和實例變數的值
        System.out.println("修改後的靜態變數的值:" + StaticVariableExample.staticVariable);
        System.out.println("修改後的實例變數的值:" + obj.instanceVariable);
    }
}
//輸出結果:
//靜態變數的值:10
//實例變數的值:20
//修改後的靜態變數的值:30
//修改後的實例變數的值:40

成員變數

成員變數(Member Variables)是定義在類中的變數,也稱為實例變數或對象屬性。它們是類的組成部分,用於存儲對象的狀態和數據。

成員變數在類的內部聲明,但在方法之外。它們可以有不同的訪問修飾符(如public、private、protected等),用於控制其可見性和訪問許可權。

每個類的實例(對象)都有自己的一組成員變數,它們獨立於其他對象的成員變數。當創建一個類的實例時,會為該實例分配一塊記憶體來存儲其成員變數的值。

成員變數可以是任何合法的Java數據類型,包括基本數據類型(如int、double、boolean等)和引用數據類型(如String、數組等)。每個對象的成員變數都有預設的初始值,例如,數值類型的預設值是0,布爾類型的預設值是false,引用類型的預設值是null。

通過使用對象引用和點操作符(.)可以訪問和修改對象的成員變數。每個對象都有自己獨立的一組成員變數,可以通過對象引用來訪問和操作屬於該對象的成員變數。

總結來說,成員變數是定義在類中的變數,用於存儲對象的狀態和數據。每個對象都有自己獨立的一組成員變數,通過對象引用和點操作符可以訪問和操作這些成員變數。

當我們定義一個類時,可以在類的內部聲明成員變數。下麵是一個示例代碼,解釋了成員變數的用法:

public class MyClass {
    // 成員變數
    private int myNumber; // 整數類型的成員變數
    private String myString; // 字元串類型的成員變數

    // 構造方法,用於創建對象時初始化成員變數
    public MyClass(int number, String str) {
        myNumber = number;
        myString = str;
    }

    // 成員方法,用於訪問成員變數和進行操作
    public void printDetails() {
        System.out.println("Number: " + myNumber);
        System.out.println("String: " + myString);
    }

    // 主方法,用於執行程式
    public static void main(String[] args) {
        // 創建一個對象並傳入初始化參數
        MyClass obj = new MyClass(10, "Hello");
        // 調用成員方法來訪問和操作成員變數
        obj.printDetails();
    }
}

在上述代碼中,我們定義了一個名為MyClass的類,並聲明瞭兩個成員變數myNumbermyString。在構造方法中,我們初始化這兩個成員變數。然後,在成員方法printDetails()中,我們訪問並列印了這兩個成員變數的值。

在主方法中,我們創建了一個MyClass對象obj,並傳入初始化參數10和"Hello"。然後,我們調用obj的成員方法printDetails(),它會輸出成員變數myNumbermyString的值。

通過這個例子,我們可以看到成員變數的用法。每個對象都有自己獨立的一組成員變數,我們可以通過對象引用來訪問和操作這些成員變數。

ArrayList和LinkedList

ArrayList和LinkedList是Java中兩種常見的集合類,它們都實現了List介面,但在內部實現和使用方式上有一些區別。

內部實現方式:
ArrayList:基於數組實現,可以利用索引進行快速訪問和修改元素。插入和刪除元素時需要移動其他元素的位置,效率較低。
LinkedList:基於雙向鏈表實現,每個元素都包含前後指針,插入和刪除元素時只需要修改相鄰元素的指針,效率較高。

訪問效率:
ArrayList:由於基於數組實現,可以通過索引進行快速訪問和修改元素。時間複雜度為O(1)。
LinkedList:由於基於鏈表實現,訪問和修改元素需要遍歷鏈表,時間複雜度為O(n),其中n為鏈表的長度。

插入和刪除效率:
ArrayList:插入和刪除元素時,需要將後續元素向後或向前移動,時間複雜度為O(n)。
LinkedList:由於基於鏈表實現,插入和刪除元素只需要修改相鄰元素的指針,時間複雜度為O(1)。但是在具體的位置插入和刪除元素時,需要先遍歷到對應位置。

記憶體占用:
ArrayList:由於是基於數組實現,需要預先分配一定大小的連續記憶體空間。如果元素數量超過數組容量,需要進行擴容操作,會占用更多的記憶體空間。
LinkedList:由於是基於鏈表實現,每個元素都包含前後指針,會消耗更多的記憶體空間。
根據上述區別,我們可以根據具體的應用場景選擇使用ArrayList或LinkedList。如果需要頻繁訪問和修改元素,並且對插入和刪除操作要求不高,可以選擇ArrayList。如果需要頻繁進行插入和刪除操作,並且訪問和修改元素的需求較少,可以選擇LinkedList。

Override

"覆蓋"(Override)和重寫(override)是面向對象編程中的一個概念,指的是在子類中重新定義父類中已有的方法。

當一個子類繼承自父類時,它可以使用父類中的方法。然而,有時子類需要對父類的方法進行修改或者定製化操作,這就是方法的覆蓋。

要進行方法的覆蓋,子類需要滿足以下條件:

  1. 子類的方法名、參數列表和返回類型必須與父類中被覆蓋的方法相同。
  2. 子類中的覆蓋方法不能擁有比父類中被覆蓋方法更為嚴格的訪問修飾符。
  3. 子類中覆蓋方法的返回類型可以是父類方法返回類型的子類。

當我們在子類中定義一個與父類中具有相同方法簽名(方法名、參數列表和返回類型)的方法時,就可以認為我們在覆蓋父類的方法。在運行時,當通過子類對象調用該方法時,將會執行子類中的方法而不是父類中的方法。

覆蓋方法的目的通常是為了在子類中實現特定的行為,使得子類能夠按照自己的邏輯來執行相同的方法名。

需要註意的是,在Java中,靜態方法不能被覆蓋(Override)。靜態方法屬於類而不是對象,並且在編譯時就確定了調用的版本。所以無論如何在子類中定義相同的靜態方法,都不會對父類中的靜態方法產生影響。

方法重載(Method Overloading)

是指在一個類中可以存在多個同名的方法,但這些方法的參數列表不同。當調用這個方法時,編譯器會根據傳入的參數的類型和數量來選擇匹配的方法進行調用。

方法重載的特點如下:

  1. 方法名相同:重載的方法必須使用相同的方法名。
  2. 參數列表不同:重載的方法必須有不同的參數列表,可以包括參數的類型、數量和順序。
  3. 返回類型可以相同或不同:重載的方法可以具有相同的返回類型,也可以具有不同的返回類型,但返回類型不是方法重載的標準。
  4. 方法重載與訪問修飾符和返回類型無關:重載的方法可以有不同的訪問修飾符(如publicprivateprotected)和返回類型(除了void)。

方法重載的目的是提供一種更靈活的方式來處理不同類型的輸入數據,使代碼更簡潔、易讀和易於維護。通過方法重載,可以使用相同的方法名來表示一組相關的操作,而不需要在方法名中使用不同的尾碼或首碼來區分。

例如,以下是一個簡單的示例,演示了方法重載的使用:

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
    
    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        
        System.out.println(calculator.add(2, 3));               // 調用int add(int a, int b)
        System.out.println(calculator.add(2.5, 3.7));           // 調用double add(double a, double b)
        System.out.println(calculator.add(2, 3, 5));            // 調用int add(int a, int b, int c)
    }
}

在上述示例中,Calculator類中定義了三個同名的方法add,它們的參數列表不同。通過傳入不同類型和數量的參數,可以調用不同的重載方法。運行程式會輸出以下結果:

5
6.2
10

通過方法重載,可以根據不同的參數類型和數量來選擇正確的方法進行調用,使代碼更加靈活和易於理解。

構造函數

構造函數是一種特殊的方法,用於在創建對象時進行初始化操作。它具有與類相同的名稱,沒有返回類型(甚至沒有void),並且在使用new關鍵字創建對象時自動調用。

下麵是一個簡單的Java代碼示例,展示了一個名為Person的類和其構造函數的定義:

public class Person {
    private String name;
    private int age;
    
    // 構造函數
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 其他方法
    public void sayHello() {
        System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
    }
    
    public static void main(String[] args) {
        // 使用構造函數創建Person對象
        Person person = new Person("John", 25);
        
        // 調用對象的方法
        person.sayHello();
    }
}

在上面的代碼中,Person類有兩個私有的成員變數name和age,以及一個公共的構造函數和一個sayHello方法。構造函數被定義為public Person(String name, int age),接受兩個參數name和age,並用於初始化對象的成員變數。

在main方法中,使用構造函數new Person("John", 25)來創建一個名為person的Person對象。然後,通過調用person對象的sayHello方法,輸出一個簡單的問候語。

構造函數在創建對象時被自動調用,用於對對象進行初始化操作,例如給成員變數賦初始值。

深拷貝和淺拷貝

淺拷貝和深拷貝是在對象複製過程中的兩種不同方式。

淺拷貝是指創建一個新對象,該對象的欄位值是原始對象欄位值的一份拷貝。如果欄位是基本類型,拷貝的就是該欄位的值;如果欄位是引用類型,拷貝的就是該欄位的引用,兩個對象將共用同一個引用。換句話說,淺拷貝只複製對象的第一層,不會遞歸地複製對象的引用類型欄位。

深拷貝是指創建一個新對象,並遞歸地複製原始對象及其所有引用類型欄位所引用的對象,直到所有引用的對象都被覆制。深拷貝會生成一個與原始對象完全獨立的副本,即使對副本對象進行修改也不會影響原始對象。

需要註意的是,深拷貝可能會導致複雜的對象關聯關係和迴圈引用問題,因此在實現深拷貝時需要考慮如何解決這些問題。

通常情況下,淺拷貝可以通過實現Cloneable介面並重寫clone()方法來實現。而深拷貝可以通過序列化和反序列化、遞歸複製或使用第三方庫等方式來實現。

下麵是一個示例代碼,演示了淺拷貝和深拷貝的區別:

class Person implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Address {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }
}

public class Example {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("Beijing");
        Person person1 = new Person("Alice", 20, address);

        // 淺拷貝
        Person person2 = (Person) person1.clone();
        System.out.println(person1.getAddress() == person2.getAddress()); // 輸出:true,引用類型欄位共用同一個引用

        // 深拷貝
        Address newAddress = new Address(person1.getAddress().getCity());
        Person person3 = new Person(person1.getName(), person1.getAge(), newAddress);
        System.out.println(person1.getAddress() == person3.getAddress()); // 輸出:false,引用類型欄位使用新的引用
    }
}

在上面的例子中,Person類包含一個引用類型欄位address,表示人的地址。我們創建了一個person1對象,並通過淺拷貝和深拷貝分別創建了person2person3對象。

在淺拷貝中,person2address欄位和person1共用同一個引用,因此它們指向的是同一個Address對象。而在深拷貝中,我們手動創建了一個新的Address對象,並將其賦給person3address欄位,使得person3person1擁有不同的地址對象。

因此,淺拷貝只複製了引用類型欄位的引用,而深拷貝複製了引用類型欄位的整個對象。


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

-Advertisement-
Play Games
更多相關文章
  • 數據過濾在數據分析過程中具有極其重要的地位,因為在真實世界的數據集中,往往存在重覆、缺失或異常的數據。pandas提供的數據過濾功能可以幫助我們輕鬆地識別和處理這些問題數據,從而確保數據的質量和準確性。 今天介紹的query函數,為我們提供了強大靈活的數據過濾方式,有助於從複雜的數據集中提取有價值的 ...
  • 目錄數組(Array)一、數組概念二、如何聲明一個數組三、如何為數組初始化1、數組本身初始化:2、數組的元素初始化2.1 一維數組2.2多維數組四、如何表示數組的各個概念五、數組記憶體和分配空間六、數組相關演算法七、十大內部排序演算法八、數組的工具類:Arrays九、數組的異常 數組(Array) 一、數 ...
  • 前言 在學習C++時,const關鍵字的知識點分散在書的各個章節。當我們嘗試在編程時使用const時,總會感覺有一些細節被遺忘,因而不能得心應手地使用const關鍵字。因此,本篇文章嘗試著對const關鍵字的做一些總結。參考書籍《C++ Primer Plus》 const總結 這裡是我做的關於co ...
  • 在Spring中,實例化Bean對象涉及構造方法的調用。通過分析源碼,我們瞭解到實例化的步驟和推斷構造方法的過程。當一個類只有一個構造方法時,Spring會根據具體情況決定是否使用該構造方法。如果一個類存在多個構造方法,就需要根據具體情況具體分析。 ...
  • polymorphism 靜態聯編和動態聯編 多態性(polymorphism)提供介面與具體實現之間的另一層隔離,從而將”what”和”how”分離開來。多態性改善了代碼的可讀性和組織性,同時也使創建的程式具有可擴展性,項目不僅在最初創建時期可以擴展,而且當項目在需要有新的功能時也能擴展。 c++ ...
  • 一、簡介 在 Java 多線程編程中,還有一個非常重要的設計模式,它就是:生產者和消費者模型。 這種模型可以充分發揮 cpu 的多線程特性,通過一些平衡手段能有效的提升系統整體處理數據的速度,減輕系統負載,提高程式的效率和穩定性,同時實現模塊之間的解耦。 那什麼是生產者和消費者模型呢? 簡單的說,生 ...
  • 下拉列表(下拉框)可以確保用戶僅從預先給定的選項中進行選擇,這樣不僅能減少數據輸入錯誤,還能節省時間提高效率。在MS Excel中,我們可以通過 “數據驗證” 提供的選項來創建下拉列表,但如果要在Java程式中通過代碼實現這一功能,可能需要藉助一些第三方庫。本文將分享兩種使用免費Java庫在Exce ...
  • Playwright是由微軟公司2020年初發佈的新一代自動化測試工具,相較於目前最常用的Selenium,它僅用一個API即可自動執行Chromium、Firefox、WebKit等主流瀏覽器自動化操作。 對各種開發語言也有非常好的支持。常用的NodeJs、Java、python都有支持,且有豐富 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...