• Java 浅拷贝会带来的问题


    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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在上面的示例代码中,我们创建了一个 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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在上面的示例代码中,我们创建了一个 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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在上面的示例代码中,我们创建了一个 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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上面的示例代码中,我们定义了一个泛型 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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

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

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

  • 相关阅读:
    Mac 安装Nodejs
    SpringBoot+Vue体育馆管理系统(前后端分离)
    7.运算符
    CompletableFuture
    Eclipse JavaEE 历史版本2015-2018
    CSAPP Data Lab
    为什么CDN能创造这么利益
    分布式事物【XA强一致性分布式事务实战、分布式架构的理论知识、TCC核心组成】(六)-全面详解(学习总结---从入门到深化)
    图像处理解决方案 veImageX 技术演进之路
    C# 使用Parallel去执行并行下载
  • 原文地址:https://blog.csdn.net/qq_49841284/article/details/134085538