Java 浅拷贝会带来的问题

news2024/11/16 2:25:10

Java 浅拷贝会带来的问题

一,常见问题

Java 中的浅拷贝是指在对象拷贝时,只复制对象的引用,而不是对象本身。这意味着浅拷贝会导致多个对象共享同一块内存空间,当一个对象修改共享内存时,其他对象也会受到影响。
在这里插入图片描述

下面是几个可能出现的问题:

  1. 对象状态被改变:如果一个对象被多个其他对象引用,当其中一个对象改变了该对象的状态,其他对象也会受到影响。这会导致程序的行为不可预测,并且很难调试。

  2. 安全问题:如果一个对象包含敏感信息,例如密码或银行账户信息,如果多个对象共享同一块内存,则其他对象可以轻松地访问这些信息,这会导致安全问题。

  3. 性能问题:如果对象拥有大量的属性和方法,则浅拷贝会在内存中创建多个指向同一对象的引用,这会导致内存占用过高,从而影响程序的性能。

因此,在设计 Java 程序时,应该谨慎使用浅拷贝,并尽可能使用深拷贝来避免以上问题。深拷贝是指在对象拷贝时,复制对象的所有属性和方法,从而创建一个新的对象,使得每个对象都拥有自己的内存空间,不会相互影响。

二,浅拷贝会带来的问题示例代码

以下是三种浅拷贝可能带来的问题的示例代码:

  1. 对象状态被改变:
public class Person implements Cloneable {
    private String name;
    private List<String> hobbies;

    public Person(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

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

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public String getName() {
        return name;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

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

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        List<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Gardening");

        Person person1 = new Person("Alice", hobbies);
        Person person2 = (Person) person1.clone();

        System.out.println("person1: " + person1.getName() + ", Hobbies: " + person1.getHobbies());
        System.out.println("person2: " + person2.getName() + ", Hobbies: " + person2.getHobbies());

        person2.getHobbies().add("Cooking");

        System.out.println("person1: " + person1.getName() + ", Hobbies: " + person1.getHobbies());
        System.out.println("person2: " + person2.getName() + ", Hobbies: " + person2.getHobbies());
    }
}

在上面的示例代码中,我们创建了一个 Person 类,其中包含一个 List 类型的 hobbies 属性。在浅拷贝过程中,person1person2 共享同一个 hobbies 对象。当我们修改其中一个对象的 hobbies 列表时,另一个对象的 hobbies 列表也会被修改,导致对象状态被改变。

  1. 安全问题:
public class BankAccount implements Cloneable {
    private String accountNumber;
    private double balance;

    public BankAccount(String accountNumber, double balance) {
        this.accountNumber = accountNumber;
        this.balance = balance;
    }

    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public double getBalance() {
        return balance;
    }

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

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        BankAccount account1 = new BankAccount("123456789", 1000.0);
        BankAccount account2 = (BankAccount) account1.clone();

        System.out.println("account1: " + account1.getAccountNumber() + ", Balance: " + account1.getBalance());
        System.out.println("account2: " + account2.getAccountNumber() + ", Balance: " + account2.getBalance());

        account2.setBalance(500.0);

        System.out.println("account1: " + account1.getAccountNumber() + ", Balance: " + account1.getBalance());
        System.out.println("account2: " + account2.getAccountNumber() + ", Balance: " + account2.getBalance());
    }
}

在上面的示例代码中,我们创建了一个 BankAccount 类,其中包含账户号码和余额信息。在浅拷贝过程中,account1account2 共享同一个 BankAccount 对象。如果其中一个对象修改了账户余额,另一个对象也会受到影响。这可能导致安全问题,例如,如果账户余额是敏感信息,其他对象可以轻松地访问和修改它。

  1. 性能问题:
public class LargeObject implements Cloneable {
    private int[] data;

    public LargeObject(int[] data) {
        this.data = data;
    }

    public void setData(int[] data) {
        this.data = data;
    }

    public int[] getData() {
        return data;
    }

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

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        int[] data = new int[1000000];
        LargeObject obj1 = new LargeObject(data);
        LargeObject obj2 = (LargeObject) obj1.clone();

        System.out.println("obj1 data length: " + obj1.getData().length);
        System.out.println("obj2 data length: " + obj2.getData().length);

        obj2.getData()[0] = 10;

        System.out.println("obj1 data length: " + obj1.getData().length);
        System.out.println("obj2 data length: " + obj2.getData().length);
    }
}

在上面的示例代码中,我们创建了一个 LargeObject 类,其中包含一个长度为 1000000 的整数数组。在浅拷贝过程中,obj1obj2 共享同一个整数数组对象,这可能导致性能问题。当我们修改 obj2 中的数组元素时,obj1 中的数组元素也会被修改,因为它们指向同一块内存。如果对象拥有大量的属性和方法,浅拷贝会导致内存占用过高,从而影响程序的性能。

三,深拷贝示例代码

以下是一个深拷贝工具类的示例代码,使用了 Java 的序列化和反序列化机制来实现深拷贝:

import java.io.*;

public class DeepCopyUtils {
    public static <T extends Serializable> T deepCopy(T object) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        return (T) ois.readObject();
    }
}

在上面的示例代码中,我们定义了一个泛型 deepCopy 方法,它接受一个实现了 Serializable 接口的对象作为参数,并返回该对象的深拷贝副本。具体实现过程与之前的示例代码相同。

对于实现了接口的对象,我们可以通过以下示例代码进行深拷贝:

public interface Shape extends Serializable {
    void draw();
}

public class Circle implements Shape {
    private int x;
    private int y;
    private int radius;

    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing Circle at (" + x + ", " + y + "), radius " + radius);
    }
}

public class DeepCopyExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Circle circle1 = new Circle(10, 20, 30);
        Circle circle2 = DeepCopyUtils.deepCopy(circle1);

        circle2.draw();
    }
}

在上面的示例代码中,我们定义了一个 Shape 接口和一个实现了该接口的 Circle 类。在 DeepCopyExample 类中,我们创建了一个 Circle 对象 circle1,并将其深拷贝到 circle2 中。最后,我们调用 circle2.draw() 方法来验证深拷贝是否成功。

需要注意的是,如果被拷贝的对象中包含了不可序列化的成员变量,那么该成员变量也无法被正确地拷贝。此外,对于非常复杂的对象图,深拷贝可能会导致性能问题。 我有更好的拷贝代码工具类有需要可以跟我要

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu下使用Docker的简单命令

1&#xff1a;要在Ubuntu下使用Docker首先需要提权&#xff0c;Ubuntu下root是没有密码的。注意前导符的变化$是普通用户&#xff0c;#是管理员。 sudo -i2&#xff1a;运行一个容器。-d是后台运行&#xff0c;-p是把http的端口号由80变成8080。 docker run -d -p 8080:80 ht…

php之 角色的权限管理(RBAC)详解

RBAC&#xff08;Role-based access control&#xff09;是一种常见的权限管理模型&#xff0c;通过将用户分配至特定的角色&#xff0c;以及为角色分配访问权限&#xff0c;实现了权限管理的目的。以下是关于RBAC的详细解释&#xff1a; 角色&#xff1a;RBAC模型的核心是角色…

[RISC-V]verilog

小明教IC-1天学会verilog(7)_哔哩哔哩_bilibili task不可综合&#xff0c;function可以综合

FL Studio21水果编曲软件如何切换成官方中文版

FL studio又被国内网友称之为水果音乐制作软件21版本&#xff0c;是Image-Line公司成立23周年而发布的一个版本&#xff0c;FL studio中文版是目前互联网上最优秀的完整的软件音乐制作环境或数字音频工作站&#xff0c;FL Studio包含了编排&#xff0c;录制&#xff0c;编辑&am…

面试题:百万数据的导入导出解决方案,怎么设计?

文章目录 前景1 传统POI的的版本优缺点比较HSSFWorkbookXSSFWorkbookSXSSFWorkbook 2 使用方式哪种看情况3 百万数据导入导出&#xff08;正菜&#xff09;想要解决问题我们首先要明白自己遇到的问题是什么&#xff1f;解决思路&#xff1a;3.1 EasyExcel 简介3.2 300w数据导出…

P1494 [国家集训队] 小 Z 的袜子

这一题是一个关于多次查询区间状态的一个问题&#xff0c;暴力肯定会超限&#xff0c;但是可以用莫队来优化暴力。 莫队的思想就是&#xff0c;用上一个区间的状态来更新当前区间的状态。 问题就是状态怎么更新以及求出当前区间的状态、也就是有多少对相同的袜子以及总共有多…

禁止chrome浏览器更新方式

1、禁用更新服务 WinR调出运行&#xff0c;输入services.msc&#xff0c;进入服务。 在服务中有两个带有Google Update字样&#xff0c;双击打开后禁用&#xff0c;并把恢复选项设置为无操作。 2、删除计划任务 运行taskschd.msc&#xff0c;打开计划任务程序库&#xff0c;在…

uniapp 中添加 vconsole

uniapp 中添加 vconsole 一、安装 vconsole npm i vconsole二、使用 vconsole 在项目的 main.js 文件中添加如下内容 // #ifdef H5 // 提交前需要注释 本地调试使用 import * as vconsole from "vconsole"; new vconsole() // 使用 vconsole // #endif三、成功

Redis中的数据类型及与Mysql数据库同步方法

1.Redis中的数据类型 Redis中的数据类型包括&#xff1a; 排行榜应选用有序集合Zset&#xff0c;原因是排行榜既要去重&#xff0c;也要排序&#xff0c;用这种结构最为合适。 2.Redis和MySQL之间的同步常见方法 要实现Redis和MySQL之间的同步&#xff0c;常见方法包括&…

为什么网上的流量卡都有禁发地区呢?流量卡管控地区整理!

在网上购买过流量卡的朋友应该都知道&#xff0c;但凡是运营商推出的大流量优惠套餐&#xff0c;在套餐详情中都是有禁发地区&#xff0c;只不过每张卡的禁发地区不同而已。 设置禁发地区的主要目的还是为了防止一些电信诈骗案件的发生&#xff0c;或者违法违规利用电话卡的情…

Windows-Oracle11g 安装详解-含Navicate远程连接配置 -本地监听设置及更换navicate环境指向的oci.dll

文章目录 1 下载地址&#xff1a;2 安装2.1 解压缩运行setup2.2 修改配置文件2.3 一直选择默认&#xff0c;直到设置口令2.4 Oracle服务启动 3 登录Oracle4 解锁普通用户scott5 简化连接&#xff08;可做可不做&#xff09;5.1 修改配置文件5.2 添加内容 6 配置本地监听6.1 修改…

正点原子嵌入式linux驱动开发——Linux RTC驱动

RTC也就是实时时钟&#xff0c;用于记录当前系统时间&#xff0c;对于Linux系统而言时间是非常重要的&#xff0c;就和使用Windows电脑或手机查看时间一样&#xff0c;在使用Linux设备的时候也需要查看时间。本章就来学习一下如何编写Linux下的RTC驱动程序。 Linux内核RTC驱动…

黑五网一来袭,卖家该如何做好旺季备货

亚马逊Prime Day大促刚刚完美落幕&#xff0c;黑五网一又将接着热度浪潮来袭&#xff0c;对于亚马逊卖家来说&#xff0c;黑五、网一是一年中非常重要的一个营销节点&#xff0c;是能让店铺销售量提升一个阶梯的重要机会。 在去年&#xff0c;美国消费者在黑五期间的消费额达到…

Java操作符

&#x1f435;由于Java的操作符和C语言的操作符有很多相同之处&#xff0c;所以本篇文章只讲解Java操作符的重点和与C语言的不同点 1. 四则运算操作符&#xff1a; - * / % 1.做除法和取模时右操作数不能为0&#xff1b; 2.取模的有操作数可以是double类型&#xff0c;但是没有…

电脑监控软件哪些比较好用

电脑监控软件在当今信息化时代越来越受到人们的关注&#xff0c;它们可以用于保护公司的商业机密&#xff0c;防止员工在工作中做一些不恰当的事情&#xff0c;以及在家庭中监控孩子的上网行为等。 本文将介绍一些比较好用的电脑监控软件&#xff1a; 一、域之盾软件 这款软件…

Linux之线程池

线程池 线程池概念线程池的应用场景线程池实现原理单例模式下线程池实现STL、智能指针和线程安全其他常见的各种锁 线程池概念 线程池&#xff1a;一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待…

【JavaSE语法】运算符

一、 什么是运算符 计算机的最基本的用途之一就是执行数学运算&#xff0c;运算符即对操作数进行操作时的符号&#xff0c;不同运算符操作的含义不同 Java中运算符可分为以下&#xff1a;算术运算符( - * /)、关系运算符(< > )、逻辑运算符、位运算符、移位运算符以及条…

第十六章 反射与注解

所有 Java 类均继承了 bjet 类&#xff0c;在 Object 类中定义了一个 getClass0方法&#xff0c;该回一个类型为Class的对象。例如下面的代码: JTextField textField new JTextField();//创建JTextField对象 Class textFieldC textField.getClass();//获取Class对象 利用Cla…

Java练习题2020-3

统计从1到N的整数中,所有立方值的平方根为整数的数的个数 输入说明&#xff1a;整数 N(N<10000)&#xff1b; 输出说明&#xff1a;符合条件的数的个数&#xff0c;如4^3648^2 输入样例&#xff1a;10 输出样例&#xff1a;3 (说明&#xff1a;样例中符合条件的3个数是1、4、…

【Linux】部署单机项目以及前后端分离项目

Linux部署单机项目&#xff1a; 优点&#xff1a; 简化了系统管理&#xff1a;由于所有服务都在同一台机器上运行&#xff0c;因此可以简化系统管理和维护。 提高了性能&#xff1a;由于没有网络延迟和其他因素的影响&#xff0c;所以可以提高系统的性能。 缺点&#xff1a; 容…