首页 > 编程语言 >Java的深浅拷贝认识

Java的深浅拷贝认识

时间:2024-05-23 14:29:36浏览次数:29  
标签:Java 对象 clone Person 深浅 引用 类型 拷贝

目录


在Java中,深拷贝和浅拷贝是对象复制的两种方式,主要区别在于对对象内部的引用类型的处理上。

浅拷贝

定义:
浅拷贝是指创建一个新的对象,但这个新对象的属性(包括引用类型的属性)仍然指向原来对象的属性。换言之,如果原对象中的属性是一个引用类型,那么浅拷贝只会复制这个引用的地址,新旧对象会共享同一块内存区域。因此,修改其中一个对象的引用类型属性时,另一个对象的相同属性也会受到影响。

优点:
省资源。

适合场景:

  • 只读取,不写入。
  • 如果对象结构简单,或者希望节省资源,浅拷贝更合适。

code:

class Person implements Cloneable {
    String name;
    Address address; // 假设Address是一个类

    public Person clone() {
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // 无法克隆的情况不应该发生
        }
    }
}

Object默认是浅拷贝。
在不重写的情况下,使用构造函数或copy()等自定义方法, 都是直接赋值引用类型字段,属于浅拷贝。

深拷贝

定义:
深拷贝不仅会创建一个新对象,还会递归地为所有引用类型的属性创建副本,确保源对象和拷贝对象之间完全独立,修改一个对象不会影响到另一个对象。

优点:
没有优点,只是说更适合写入操作。

适合场景:

  • 需要写入操作。
  • 需要完全独立的副本,避免修改时的相互影响,应选择深拷贝

重写cloe方法实现深拷贝:

// 对于每个引用类型的属性,手动调用其拷贝方法(如果该类也支持深拷贝的话)来创建新的实例。
class Person implements Cloneable {
    String name;
    Address address;

    public Person deepClone() {
        Person clone = new Person();
        clone.name = this.name;
        clone.address = this.address.clone(); // 假设Address类也实现了深拷贝
        return clone;
    }
}

注意:深拷贝需要注意嵌套的引用类型是否也实现了重写问题,不然嵌套类还是对类型的引用的浅拷贝。

背景解释:
引用数据类型指的是类、接口、数组等数据类型,与之相对的是基本数据类型,如int、double、boolean等。

实现深拷贝的方法:

  • 重写clone()方法来实现深拷贝
  • 使用第三方库如Apache Commons Lang等
  • 手动实现深拷贝逻辑
  • 序列化方式实现深拷贝
  • ...

分辨代码里的深浅拷贝

赋值:
当一个对象实例被赋值给另一个变量时(例如 Object obj2 = obj1;),无论是在方法参数传递还是普通变量赋值中,如果不进行特殊处理,这总是浅拷贝。两个变量实际上指向内存中的同一个对象。

方法参数传递:
在Java中,方法参数传递本质上是值传递。当对象作为参数传递给方法时,传递的是对象引用的副本(即指针的拷贝),而不是对象本身的新拷贝。因此,方法内对对象内容的修改会影响原始对象,这是浅拷贝行为。但如果方法内部创建了对象的新实例并返回,则可以实现深拷贝。

方法调用时,检查是否仅传递了引用还是进行了对象内容的实际复制。
查看代码中是否有显式地为引用类型字段创建新实例的逻辑,这是深拷贝的关键标志。

注意:基本数据类型与引用类型有区别,基本数据类型的赋值总是按值传递,不会涉及深浅拷贝问题。

标签:Java,对象,clone,Person,深浅,引用,类型,拷贝
From: https://www.cnblogs.com/mysticbinary/p/18207601

相关文章

  • #Java集合的组内平均值的计算方法
    要计算Java集合(例如List或Set中的Integer、Double或其他数值类型的对象)的组内平均值,我们需要遍历这个集合,累加所有的元素值,然后除以集合的大小(即元素的数量)。以下是一个详细的步骤说明和完整的代码示例。1.步骤说明(1)创建集合:首先,我们需要一个包含数值的集合。在这个例子中,我们将......
  • Java静态变量在静态方法内部无法改变值
    一、如何解决“Java静态变量在静态方法内部无法改变值”的问题在Java中,静态变量(也称为类变量)属于类本身,而不是类的任何特定实例。它们可以在没有创建类的实例的情况下访问和修改。如果我们发现在静态方法内部无法改变静态变量的值,这通常是因为我们的代码中有一些逻辑错误或误解。......
  • JAVA面试题
    第一章-Java基础篇1、你是怎样理解OOP面向对象难度系数:⭐2、重载与重写区别难度系数:⭐3、接口与抽象类的区别难度系数:⭐4、深拷贝与浅拷贝的理解难度系数:⭐5、sleep和wait区别难度系数:⭐6、什么是自动拆装箱int和Integer有什么区别难度系数:⭐7、......
  • java注解
    一、前言最近在看B站颜群老师的课程,Javaweb>spring>springMVC>mybatis>spring高级,一路走来,跌跌撞撞,发现spring也不过尔尔,说白了,spring就是想尽办法将new做的更简单,更完美,更可配置。Spring的一个核心功能是IOC,就是将Bean初始化加载到容器中,Bean是如何加载到容器的,可以使用Spring......
  • Java如何显示不同字体的文字?
    Java如何显示不同字体的文字?在Java的GUI编程中,如何显示不同字体的文字?以下示例演示如何使用Font类的setFont()方法显示不同字体的文本。packagecom.yiibai;importjava.awt.*;importjava.awt.event.*;importjavax.swing.*;publicclassDisplayTextFontextendsJPane......
  • 浅谈一下C#和java的线程不同点
    C#和Java在线程处理方面有一些显著的区别,这些区别主要体现在线程的创建、管理和生命周期控制上。以下是一些主要的区别:线程的创建和管理Java:Java中线程的创建通常是通过继承Thread类或实现Runnable接口来实现的。Java提供了线程组(ThreadGroup)的概念,允许将线程组织在一起......
  • Java-黄金矿工(合)
    目录效果主要思想实现1.矿工(Miner.java)2.金块(Object.java)3.矿工的线(Line.java)4.粉色小球(Hook.java)5.背景(Bg.java)6.游戏界面(GameFrame.java)7.Server.java8.ServerThread.java9.Client.java10.ClientThread.java11.OpenThread.java12.publicMeans.java编辑器:IDEA语言:Java主要技术......
  • Java-黄金矿工(二)
    目录实现1-2创建服务端和客户端3.游戏界面实现(1)新建GameFrame类(游戏界面)(2)各小类①Bg.java(背景类)②Miner.java(矿工类)③Line.java(线类)④Hook.java(钩子类)⑤Object.java(金块)(3)在GameFrame中调用各小类①创建变量②创建金块③绘制画面④创建传递变量⑤创建定时器⑥创建判断赢家的方法⑦......
  • Java-黄金矿工(一)
    目录效果主要思想实现1.准备图片(1)背景图(2)金块(3)矿工(4)钩子2.服务端与客户端搭建(1)新建Server类(2)添加基本元素(3)新建launch方法(4)新建公共类publicMeans(5)创建线程类ServerThread(6)在Server类中建立服务端(7)调用建立服务端方法(8)在Server类中建立发送信息的方法(9)在main方法中调用launch方法(1......
  • 2024年最新java(高级)面试题
    1.创建对象的几种方式使用new关键字:使用new关键字可以在堆内存中创建一个新的对象。通过反射机制:通过Java反射机制,可以在运行时动态地获取类的信息并创建对象。这种方式可以通过Class类的newInstance()方法或Constructor类的newInstance()方法来创建对象。Clas......