总结的Java知识点集合

冬雨财经  金牌会员 | 2024-5-12 22:16:23 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 858|帖子 858|积分 2574

这是我读大学时的Java知识点总结,还不全面,后续会渐渐增加完善。
知识点集合

实例变量

实例变量是指在类中声明的变量,其值是针对类的每个实例而独立存储的。每个类的实例都有自己的一组实例变量,它们的值可以在对象创建时初始化,并在整个对象的生命周期中保持稳定或者随着对象的状态而改变。
实例变量也被称为对象变量,因为它们是在类的对象实例化时创建的,而且每个对象都有自己的一组实例变量。
实例变量的特点包括:

  • 它们属于对象,而不是类自己。
  • 每个对象都有自己的一组实例变量,每个对象的实例变量值可以是不同的。
  • 它们在对象的整个生命周期中存在,而且可以被对象的方法访问和修改。
  • 实例变量不能利用 static 关键字进行修饰,而是通过实例化对象来访问。
以下是一个示例,演示了怎样在Java中定义和利用实例变量:
  1. public class Person {
  2.     // 实例变量
  3.     String name;
  4.     int age;
  5.    
  6.     public void displayInfo() {
  7.         System.out.println("Name: " + name);
  8.         System.out.println("Age: " + age);
  9.     }
  10. }
  11. // 创建对象并设置实例变量的值
  12. Person person = new Person();
  13. person.name = "John";
  14. person.age = 25;
  15. // 调用方法访问和使用实例变量
  16. person.displayInfo();
复制代码
在这个例子中,Person 类有两个实例变量 name 和 age,它们属于每个 Person 对象的一部分。在创建 Person 对象后,可以通过访问对象的实例变量来设置和获取它们的值。在 displayInfo() 方法中,可以利用实例变量来展示对象的信息。
因此,实例变量是定义在类中的变量,每个对象都有自己独立的一组实例变量,用于存储对象的状态和属性。
实例化对象

实例化对象是根据类的定义创建一个详细的对象,也可以说是将类实例化为对象的过程。
在面向对象编程中,类是对象的模板,形貌了对象应该具有的属性和行为。通过实例化对象,我们可以根据类的定义创建一个详细的实体,该实体具有类中定义的属性和行为。
在Java中,通过利用 new 关键字和类的构造方法来实例化对象。构造方法是一种特殊的方法,用于创建对象并初始化其属性。
以下是一个示例:
  1. // 定义一个类
  2. class Person {
  3.     private String name;
  4.     private int age;
  5.    
  6.     // 构造方法
  7.     public Person(String name, int age) {
  8.         this.name = name;
  9.         this.age = age;
  10.     }
  11.    
  12.     // 方法
  13.     public void sayHello() {
  14.         System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
  15.     }
  16. }
  17. public class Main {
  18.     public static void main(String[] args) {
  19.         // 实例化对象
  20.         Person person = new Person("John", 25);
  21.         
  22.         // 调用对象的方法
  23.         person.sayHello(); // 输出 "Hello, my name is John and I'm 25 years old."
  24.     }
  25. }
复制代码
在上面的示例中,我们定义了一个 Person 类,具有 name 和 age 属性,以及 sayHello() 方法。通过 new 关键字和 Person 类的构造方法,我们实例化了一个 Person 对象,并将其赋值给 person 变量。
通过 person 对象,我们可以调用 sayHello() 方法,该方法会输出对象的属性值。
实例化对象是面向对象编程的基本概念之一,它答应我们创建详细的对象实例,并根据类定义的属性和行为进行操作。
抽象类

Java 中的抽象类是不能被实例化的,只能被继续。抽象类是用来作为其他类的父类或基类,它自己不能被实例化为对象。
抽象类是通过在类定义中利用关键字 abstract 来标识的。抽象类可以包罗抽象方法,这些方法没有详细的实现,需要在子类中进行重写实现。抽象类可以有普通方法和成员变量,可以提供一些共享的实现逻辑给子类利用。
以下是一个示例:
  1. // 抽象类
  2. abstract class Animal {
  3.     // 抽象方法
  4.     public abstract void makeSound();
  5.    
  6.     // 普通方法
  7.     public void sleep() {
  8.         System.out.println("Animal is sleeping");
  9.     }
  10. }
  11. // 继承抽象类
  12. class Cat extends Animal {
  13.     // 实现抽象方法
  14.     public void makeSound() {
  15.         System.out.println("Meow");
  16.     }
  17. }
  18. public class Main {
  19.     public static void main(String[] args) {
  20.         // 错误示例,不能实例化抽象类
  21.         // Animal animal = new Animal();
  22.         
  23.         // 创建子类对象
  24.         Animal cat = new Cat();
  25.         cat.makeSound(); // 输出 "Meow"
  26.         cat.sleep(); // 输出 "Animal is sleeping"
  27.     }
  28. }
复制代码
在上面的示例中,Animal 类是一个抽象类,其中包罗了一个抽象方法 makeSound() 和一个普通方法 sleep()。不能直接实例化 Animal 类,但可以通过继续它的子类 Cat 来创建对象。
多态性

Java 中的多态性(polymorphism)是指在一个类条理布局中,子类可以以自己的情势重写父类的方法,而且可以利用父类的引用来引用子类的对象。这种特性答应我们通过父类的引用来调用子类特定的方法,从而实现不同范例的对象以相同的方式进行操作。
多态性是面向对象编程的重要特性之一,它提高了代码的灵活性和可扩展性。通过多态性,我们可以编写通用的代码,而不需要针对每个详细的子类编写独立的代码。
以下是一个示例:
  1. // 父类
  2. class Animal {
  3.     public void makeSound() {
  4.         System.out.println("Animal makes a sound");
  5.     }
  6. }
  7. // 子类1
  8. class Dog extends Animal {
  9.     public void makeSound() {
  10.         System.out.println("Dog barks");
  11.     }
  12. }
  13. // 子类2
  14. class Cat extends Animal {
  15.     public void makeSound() {
  16.         System.out.println("Cat meows");
  17.     }
  18. }
  19. public class Main {
  20.     public static void main(String[] args) {
  21.         Animal animal1 = new Dog(); // 子类对象赋值给父类引用
  22.         Animal animal2 = new Cat(); // 子类对象赋值给父类引用
  23.         
  24.         animal1.makeSound(); // 调用子类的方法,输出 "Dog barks"
  25.         animal2.makeSound(); // 调用子类的方法,输出 "Cat meows"
  26.     }
  27. }
复制代码
在上面的示例中,我们定义了一个 Animal 父类和两个子类 Dog 和 Cat。通过将子类对象赋值给父类引用,我们可以利用父类的引用来调用子类的方法。在 main 方法中,我们创建了一个 Dog 对象,并将其赋值给 Animal 范例的引用 animal1,以及创建了一个 Cat 对象,并将其赋值给 Animal 范例的引用 animal2。然后,我们通过这两个引用调用了 makeSound() 方法,分别输出了相应的子类特定的声音。
子类不能覆盖父类的私有(private)方法

在 Java 中,子类不能覆盖父类的私有(private)方法。私有方法是指只能在声明它的类内部访问的方法,无法被其他类或子类所访问。
子类继续父类的方法有以下几种情况:

  • 如果父类的方法是公共(public)或受保护(protected)的,子类可以重写(覆盖)该方法。
  • 如果父类的方法是默认访问修饰符(即没有修饰符)的,子类可以重写该方法,前提是子类与父类在同一个包中。
  • 如果父类的方法是私有的,子类无法访问该方法,因此也无法重写它。
以下是一个示例:
  1. class Parent {
  2.     public void publicMethod() {
  3.         System.out.println("Parent's public method");
  4.     }
  5.    
  6.     protected void protectedMethod() {
  7.         System.out.println("Parent's protected method");
  8.     }
  9.    
  10.     private void privateMethod() {
  11.         System.out.println("Parent's private method");
  12.     }
  13. }
  14. class Child extends Parent {
  15.     // 重写父类的公共方法
  16.     public void publicMethod() {
  17.         System.out.println("Child's public method");
  18.     }
  19.    
  20.     // 重写父类的受保护方法
  21.     protected void protectedMethod() {
  22.         System.out.println("Child's protected method");
  23.     }
  24.    
  25.     // 无法重写父类的私有方法,编译报错
  26.     // private void privateMethod() {
  27.     //     System.out.println("Child's private method");
  28.     // }
  29. }
  30. public class Main {
  31.     public static void main(String[] args) {
  32.         Parent parent = new Parent();
  33.         parent.publicMethod(); // 输出 "Parent's public method"
  34.         parent.protectedMethod(); // 输出 "Parent's protected method"
  35.         // parent.privateMethod(); // 编译报错,私有方法无法访问
  36.         
  37.         Child child = new Child();
  38.         child.publicMethod(); // 输出 "Child's public method"
  39.         child.protectedMethod(); // 输出 "Child's protected method"
  40.     }
  41. }
复制代码
在上面的示例中,我们定义了一个 Parent 父类和一个 Child 子类。父类中有三个方法,分别是公共方法、受保护方法和私有方法。子类继续了父类,并重写了父类的公共方法和受保护方法。然而,子类无法重写父类的私有方法,因为私有方法只能在父类内部访问。
Runnable 接口并实现 run() 方法

Runnable 是一个接口,其中定义了一个抽象方法 run(),该方法包罗线程的实行逻辑。实现了 Runnable 接口的类需要实现 run() 方法,并在该方法中编写线程的详细实行逻辑。
创建线程的步骤如下:

  • 创建一个类,实现 Runnable 接口。比方:
  1. public class MyRunnable implements Runnable {
  2.     public void run() {
  3.         // 线程的执行逻辑
  4.         System.out.println("Thread is running.");
  5.     }
  6. }
复制代码

  • 在实现了 Runnable 接口的类中,编写线程的详细实行逻辑,即在 run() 方法中定义线程的行为。
  • 在主线程或其他线程中,创建 Thread 对象,并将实现了 Runnable 接口的类的实例作为参数传递给 Thread 的构造函数。比方:
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         // 创建实现了 Runnable 接口的类的实例
  4.         MyRunnable myRunnable = new MyRunnable();
  5.         // 创建 Thread 对象,并将实现了 Runnable 接口的类的实例作为参数传递
  6.         Thread thread = new Thread(myRunnable);
  7.         // 启动线程
  8.         thread.start();
  9.     }
  10. }
复制代码
通过将实现了 Runnable 接口的类的实例传递给 Thread 的构造函数,可以创建一个新的线程,并在该线程中实行实现了 run() 方法的代码逻辑。
这种方式的上风是可以实现多重继续,因为 Java 不支持多重继续,但可以实现多个接口。同时,它也更加灵活,因为同一个 Runnable 对象可以被多个线程共享,从而实现线程的资源共享。
总之,通过实现 Runnable 接口并实现 run() 方法,可以创建一个新的类作为线程的实行体,并在创建线程时将该类的实例传递给 Thread 对象来创建新线程。
先进后出(LIFO)

先进后出(Last-In-First-Out,LIFO)是一种数据布局,其中最后插入的元素首先被访问或删除。以下是实现先进后出的一些常见数据布局:

  • 堆栈(Stack):堆栈是一种基于 LIFO 原则的数据布局,它利用 push() 方法将元素添加到栈的顶部,并利用 pop() 方法从栈的顶部删除和访问元素。
  • 递归调用:在编程中,递归调用也可以看作是一种先进后出的行为。每次进行递归调用时,当前的函数调用被暂停并推入调用栈,直到递归结束开始逐个弹出并实行。
需要注意的是,先进后出是与先进先出(FIFO)相对的概念。在先进后出的数据布局中,最后插入的元素首先被访问或删除;而在先进先出的数据布局中,开始插入的元素首先被访问或删除。
先进先出(FIFO)

JAVA非常

在 Java 中,非常分为两种范例:编译时非常(Checked Exception)和运行时非常(Runtime Exception)。
编译时非常(Checked Exception)是在编译阶段检测到的非常,需要在代码中进行处置惩罚或声明抛出。它们通常表现步调在运行过程中可能出现的外部因素引起的错误或非常情况。IOException 是编译时非常的一个常见例子,表现输入输出操作可能出现的错误,比方文件不存在或读写错误等。
运行时非常(Runtime Exception)是在步调运行时发生的非常,不需要在代码中进行欺压处置惩罚或声明抛出。它们通常表现步调逻辑错误或编程错误,比方除以零、数组越界等。RuntimeException 是运行时非常的一个常见例子。
静态方法

静态方法是在类级别上定义的方法,与特定的对象实例无关。它属于类自己,而不是类的实例。可以通过类名直接调用静态方法,而无需创建类的对象。
  1. public class MyClass {
  2.     private static int count; // 静态变量
  3.     public static void staticMethod() {
  4.         System.out.println("这是一个静态方法");
  5.     }
  6.     public void instanceMethod() {
  7.         System.out.println("这是一个实例方法");
  8.     }
  9.     public static int getCount() {
  10.         return count;
  11.     }
  12.     public static void setCount(int value) {
  13.         count = value;
  14.     }
  15. }
复制代码
在上面的代码中,我们定义了一个名为MyClass的类。其中包罗一个静态方法staticMethod()和一个实例方法instanceMethod()。另有一个静态变量count,并提供了静态的getter和setter方法。
可以通过以下方式调用静态方法和访问静态变量:
  1. MyClass.staticMethod(); // 调用静态方法
  2. MyClass myObject = new MyClass();
  3. myObject.instanceMethod(); // 调用实例方法
  4. int currentCount = MyClass.getCount(); // 获取静态变量的值
  5. MyClass.setCount(10); // 设置静态变量的值
复制代码
请注意,静态方法可以直接通过类名调用,而实例方法需要通过类的对象调用。静态方法可以在没有类的实例的情况下利用,因为它们属于类自己。而实例方法需要通过类的对象来调用,因为它们与特定的对象实例相关联。
静态变量
  1. public class StaticVariableExample {
  2.     // 静态变量
  3.     static int staticVariable = 10;
  4.     // 实例变量
  5.     int instanceVariable = 20;
  6.     public static void main(String[] args) {
  7.         // 直接通过类名访问静态变量
  8.         System.out.println("静态变量的值:" + StaticVariableExample.staticVariable);
  9.         // 创建类的实例对象
  10.         StaticVariableExample obj = new StaticVariableExample();
  11.         // 通过实例对象访问实例变量
  12.         System.out.println("实例变量的值:" + obj.instanceVariable);
  13.         // 修改静态变量的值
  14.         StaticVariableExample.staticVariable = 30;
  15.         // 修改实例变量的值
  16.         obj.instanceVariable = 40;
  17.         // 再次访问静态变量和实例变量的值
  18.         System.out.println("修改后的静态变量的值:" + StaticVariableExample.staticVariable);
  19.         System.out.println("修改后的实例变量的值:" + obj.instanceVariable);
  20.     }
  21. }
  22. //输出结果:
  23. //静态变量的值:10
  24. //实例变量的值:20
  25. //修改后的静态变量的值:30
  26. //修改后的实例变量的值:40
复制代码
成员变量

成员变量(Member Variables)是定义在类中的变量,也称为实例变量或对象属性。它们是类的组成部分,用于存储对象的状态和数据。
成员变量在类的内部声明,但在方法之外。它们可以有不同的访问修饰符(如public、private、protected等),用于控制其可见性和访问权限。
每个类的实例(对象)都有自己的一组成员变量,它们独立于其他对象的成员变量。当创建一个类的实例时,会为该实例分配一块内存来存储其成员变量的值。
成员变量可以是任何合法的Java数据范例,包括基本数据范例(如int、double、boolean等)和引用数据范例(如String、数组等)。每个对象的成员变量都有默认的初始值,比方,数值范例的默认值是0,布尔范例的默认值是false,引用范例的默认值是null。
通过利用对象引用和点操作符(.)可以访问和修改对象的成员变量。每个对象都有自己独立的一组成员变量,可以通过对象引用来访问和操作属于该对象的成员变量。
总结来说,成员变量是定义在类中的变量,用于存储对象的状态和数据。每个对象都有自己独立的一组成员变量,通过对象引用和点操作符可以访问和操作这些成员变量。
当我们定义一个类时,可以在类的内部声明成员变量。下面是一个示例代码,表明了成员变量的用法:
  1. public class MyClass {
  2.     // 成员变量
  3.     private int myNumber; // 整数类型的成员变量
  4.     private String myString; // 字符串类型的成员变量
  5.     // 构造方法,用于创建对象时初始化成员变量
  6.     public MyClass(int number, String str) {
  7.         myNumber = number;
  8.         myString = str;
  9.     }
  10.     // 成员方法,用于访问成员变量和进行操作
  11.     public void printDetails() {
  12.         System.out.println("Number: " + myNumber);
  13.         System.out.println("String: " + myString);
  14.     }
  15.     // 主方法,用于执行程序
  16.     public static void main(String[] args) {
  17.         // 创建一个对象并传入初始化参数
  18.         MyClass obj = new MyClass(10, "Hello");
  19.         // 调用成员方法来访问和操作成员变量
  20.         obj.printDetails();
  21.     }
  22. }
复制代码
在上述代码中,我们定义了一个名为MyClass的类,并声明白两个成员变量myNumber和myString。在构造方法中,我们初始化这两个成员变量。然后,在成员方法printDetails()中,我们访问并打印了这两个成员变量的值。
在主方法中,我们创建了一个MyClass对象obj,并传入初始化参数10和"Hello"。然后,我们调用obj的成员方法printDetails(),它会输出成员变量myNumber和myString的值。
通过这个例子,我们可以看到成员变量的用法。每个对象都有自己独立的一组成员变量,我们可以通过对象引用来访问和操作这些成员变量。
ArrayList和LinkedList
  1. ArrayList和LinkedList是Java中两种常见的集合类,它们都实现了List接口,但在内部实现和使用方式上有一些区别。
  2. 内部实现方式:
  3. ArrayList:基于数组实现,可以利用索引进行快速访问和修改元素。插入和删除元素时需要移动其他元素的位置,效率较低。
  4. LinkedList:基于双向链表实现,每个元素都包含前后指针,插入和删除元素时只需要修改相邻元素的指针,效率较高。
  5. 访问效率:
  6. ArrayList:由于基于数组实现,可以通过索引进行快速访问和修改元素。时间复杂度为O(1)。
  7. LinkedList:由于基于链表实现,访问和修改元素需要遍历链表,时间复杂度为O(n),其中n为链表的长度。
  8. 插入和删除效率:
  9. ArrayList:插入和删除元素时,需要将后续元素向后或向前移动,时间复杂度为O(n)。
  10. LinkedList:由于基于链表实现,插入和删除元素只需要修改相邻元素的指针,时间复杂度为O(1)。但是在具体的位置插入和删除元素时,需要先遍历到对应位置。
  11. 内存占用:
  12. ArrayList:由于是基于数组实现,需要预先分配一定大小的连续内存空间。如果元素数量超过数组容量,需要进行扩容操作,会占用更多的内存空间。
  13. LinkedList:由于是基于链表实现,每个元素都包含前后指针,会消耗更多的内存空间。
  14. 根据上述区别,我们可以根据具体的应用场景选择使用ArrayList或LinkedList。如果需要频繁访问和修改元素,并且对插入和删除操作要求不高,可以选择ArrayList。如果需要频繁进行插入和删除操作,并且访问和修改元素的需求较少,可以选择LinkedList。
复制代码
Override

"覆盖"(Override)和重写(override)是面向对象编程中的一个概念,指的是在子类中重新定义父类中已有的方法。
当一个子类继续自父类时,它可以利用父类中的方法。然而,偶然子类需要对父类的方法进行修改或者定制化操作,这就是方法的覆盖。
要进行方法的覆盖,子类需要满足以下条件:

  • 子类的方法名、参数列表和返回范例必须与父类中被覆盖的方法相同。
  • 子类中的覆盖方法不能拥有比父类中被覆盖方法更为严格的访问修饰符。
  • 子类中覆盖方法的返回范例可以是父类方法返回范例的子类。
当我们在子类中定义一个与父类中具有相同方法签名(方法名、参数列表和返回范例)的方法时,就可以认为我们在覆盖父类的方法。在运行时,当通过子类对象调用该方法时,将会实行子类中的方法而不是父类中的方法。
覆盖方法的目标通常是为了在子类中实现特定的行为,使得子类可以或许按照自己的逻辑来实行相同的方法名。
需要注意的是,在Java中,静态方法不能被覆盖(Override)。静态方法属于类而不是对象,而且在编译时就确定了调用的版本。所以无论怎样在子类中定义相同的静态方法,都不会对父类中的静态方法产生影响。
方法重载(Method Overloading)

是指在一个类中可以存在多个同名的方法,但这些方法的参数列表不同。当调用这个方法时,编译器会根据传入的参数的范例和数目来选择匹配的方法进行调用。
方法重载的特点如下:

  • 方法名相同:重载的方法必须利用相同的方法名。
  • 参数列表不同:重载的方法必须有不同的参数列表,可以包括参数的范例、数目和次序。
  • 返回范例可以相同或不同:重载的方法可以具有相同的返回范例,也可以具有不同的返回范例,但返回范例不是方法重载的标准。
  • 方法重载与访问修饰符和返回范例无关:重载的方法可以有不同的访问修饰符(如public、private、protected)和返回范例(除了void)。
方法重载的目标是提供一种更灵活的方式来处置惩罚不同范例的输入数据,使代码更轻便、易读和易于维护。通过方法重载,可以利用相同的方法名来表现一组相关的操作,而不需要在方法名中利用不同的后缀或前缀来区分。
比方,以下是一个简朴的示例,演示了方法重载的利用:
  1. public class Calculator {
  2.     public int add(int a, int b) {
  3.         return a + b;
  4.     }
  5.    
  6.     public double add(double a, double b) {
  7.         return a + b;
  8.     }
  9.    
  10.     public int add(int a, int b, int c) {
  11.         return a + b + c;
  12.     }
  13.    
  14.     public static void main(String[] args) {
  15.         Calculator calculator = new Calculator();
  16.         
  17.         System.out.println(calculator.add(2, 3));               // 调用int add(int a, int b)
  18.         System.out.println(calculator.add(2.5, 3.7));           // 调用double add(double a, double b)
  19.         System.out.println(calculator.add(2, 3, 5));            // 调用int add(int a, int b, int c)
  20.     }
  21. }
复制代码
在上述示例中,Calculator类中定义了三个同名的方法add,它们的参数列表不同。通过传入不同范例和数目的参数,可以调用不同的重载方法。运行步调会输出以下结果:
  1. 5
  2. 6.2
  3. 10
复制代码
通过方法重载,可以根据不同的参数范例和数目来选择正确的方法进行调用,使代码更加灵活和易于理解。
构造函数

构造函数是一种特殊的方法,用于在创建对象时进行初始化操作。它具有与类相同的名称,没有返回范例(甚至没有void),而且在利用new关键字创建对象时自动调用。
下面是一个简朴的Java代码示例,展示了一个名为Person的类和其构造函数的定义:
  1. public class Person {
  2.     private String name;
  3.     private int age;
  4.    
  5.     // 构造函数
  6.     public Person(String name, int age) {
  7.         this.name = name;
  8.         this.age = age;
  9.     }
  10.    
  11.     // 其他方法
  12.     public void sayHello() {
  13.         System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
  14.     }
  15.    
  16.     public static void main(String[] args) {
  17.         // 使用构造函数创建Person对象
  18.         Person person = new Person("John", 25);
  19.         
  20.         // 调用对象的方法
  21.         person.sayHello();
  22.     }
  23. }
复制代码
在上面的代码中,Person类有两个私有的成员变量name和age,以及一个公共的构造函数和一个sayHello方法。构造函数被定义为public Person(String name, int age),接受两个参数name和age,并用于初始化对象的成员变量。
在main方法中,利用构造函数new Person("John", 25)来创建一个名为person的Person对象。然后,通过调用person对象的sayHello方法,输出一个简朴的问候语。
构造函数在创建对象时被自动调用,用于对对象进行初始化操作,比方给成员变量赋初始值。
深拷贝和浅拷贝

浅拷贝和深拷贝是在对象复制过程中的两种不同方式。
浅拷贝是指创建一个新对象,该对象的字段值是原始对象字段值的一份拷贝。如果字段是基本范例,拷贝的就是该字段的值;如果字段是引用范例,拷贝的就是该字段的引用,两个对象将共享同一个引用。换句话说,浅拷贝只复制对象的第一层,不会递归地复制对象的引用范例字段。
深拷贝是指创建一个新对象,并递归地复制原始对象及其所有引用范例字段所引用的对象,直到所有引用的对象都被复制。深拷贝会天生一个与原始对象完全独立的副本,即使对副本对象进行修改也不会影响原始对象。
需要注意的是,深拷贝可能会导致复杂的对象关联关系和循环引用问题,因此在实现深拷贝时需要考虑怎样办理这些问题。
通常情况下,浅拷贝可以通过实现Cloneable接口并重写clone()方法来实现。而深拷贝可以通过序列化和反序列化、递归复制或利用第三方库等方式来实现。
下面是一个示例代码,演示了浅拷贝和深拷贝的区别:
  1. class Person implements Cloneable {
  2.     private String name;
  3.     private int age;
  4.     private Address address;
  5.     public Person(String name, int age, Address address) {
  6.         this.name = name;
  7.         this.age = age;
  8.         this.address = address;
  9.     }
  10.     public void setName(String name) {
  11.         this.name = name;
  12.     }
  13.     public void setAge(int age) {
  14.         this.age = age;
  15.     }
  16.     public void setAddress(Address address) {
  17.         this.address = address;
  18.     }
  19.     public String getName() {
  20.         return name;
  21.     }
  22.     public int getAge() {
  23.         return age;
  24.     }
  25.     public Address getAddress() {
  26.         return address;
  27.     }
  28.     @Override
  29.     public Object clone() throws CloneNotSupportedException {
  30.         return super.clone();
  31.     }
  32. }
  33. class Address {
  34.     private String city;
  35.     public Address(String city) {
  36.         this.city = city;
  37.     }
  38.     public void setCity(String city) {
  39.         this.city = city;
  40.     }
  41.     public String getCity() {
  42.         return city;
  43.     }
  44. }
  45. public class Example {
  46.     public static void main(String[] args) throws CloneNotSupportedException {
  47.         Address address = new Address("Beijing");
  48.         Person person1 = new Person("Alice", 20, address);
  49.         // 浅拷贝
  50.         Person person2 = (Person) person1.clone();
  51.         System.out.println(person1.getAddress() == person2.getAddress()); // 输出:true,引用类型字段共享同一个引用
  52.         // 深拷贝
  53.         Address newAddress = new Address(person1.getAddress().getCity());
  54.         Person person3 = new Person(person1.getName(), person1.getAge(), newAddress);
  55.         System.out.println(person1.getAddress() == person3.getAddress()); // 输出:false,引用类型字段使用新的引用
  56.     }
  57. }
复制代码
在上面的例子中,Person类包罗一个引用范例字段address,表现人的地址。我们创建了一个person1对象,并通过浅拷贝和深拷贝分别创建了person2和person3对象。
在浅拷贝中,person2的address字段和person1共享同一个引用,因此它们指向的是同一个Address对象。而在深拷贝中,我们手动创建了一个新的Address对象,并将其赋给person3的address字段,使得person3和person1拥有不同的地址对象。
因此,浅拷贝只复制了引用范例字段的引用,而深拷贝复制了引用范例字段的整个对象。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表