栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

Java拷贝(赋值、浅拷贝、深拷贝)

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java拷贝(赋值、浅拷贝、深拷贝)

文章目录
  • 拷贝
    • 直接赋值
    • 浅拷贝
      • 实现方式
      • 特殊情况
    • 深拷贝
      • 实现方式
      • 多层克隆


拷贝

直接赋值

直接赋值的方式没有生产新的对象,只是生新增了一个对象引用

浅拷贝

如果原型对象的成员变量是值类型,将复制一份给克隆对象,也就是说在堆中拥有独立的空间;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。换句话说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

实现方式

被复制类需要实现 Cloneable 接口,重写 clone 方法即可,对 person 类进行改造,使其可以支持浅拷贝。

public class Person implements Cloneable {
    private String name;   // 姓名
    private int age;             // 年龄
    private String email;    // 邮件
    private String desc;      // 描述
    private Person friend; // 朋友 
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
特殊情况
public class PersonApp {
    public static void main(String[] args) throws Exception {
        // 初始化一个对象
        Person person = new Person("张三",20,"123456@qq.com","我是张三");
        // 复制对象
        Person person1 = (Person) person.clone();
        // 改变 person1 的属性值
        person1.setName("我是张三的克隆对象");
        // 修改 person age 的值
        person1.setAge(22);
        System.out.println("person对象:"+person);
        System.out.println();
        System.out.println("person1对象:"+person1);
    }
}
// person对象:Person{name='张三', age=20, email='123456@qq.com', desc='我是张三'}
// person1对象:Person{name='我是张三的克隆对象', age=22, email='123456@qq.com', desc='我是张三'}

原因:

  1. String 和 Integer 等包装类都是不可变的对象。
  2. 当需要 修改 不可变对象的值时,需要在内存中生成一个新的对象来存放新的值,然后将原来的引用指向新的地址。
  3. 所以在这里我们修改了 person1 对象的 name 属性值,person1 对象的 name 字段指向了内存中新的 name 对象,但是我们并没有改变 person 对象的 name 字段的指向,所以 person 对象的 name 还是指向内存中原来的 name 地址,也就没有变化
深拷贝

相对于浅拷贝,深拷贝是一种完全拷贝,无论是值类型还是引用类型都会完完全全的拷贝一份,在内存中生成一个新的对象。拷贝对象和被拷贝对象没有任何关系,互不影响。

实现方式
  1. 实现Cloneable接口
  2. 实现Serializable接口

实现Cloneable接口:

clone 方法不能是简单的调用super的clone()。

class Address{
	String name;
	String eCode;
	public Address(	String na, String eC;)
	{
		this.name = na;
		this.eCode = eC;
	}
}

public class Person implements Cloneable {
    private String name;   // 姓名
    private int age;             // 年龄
    private String email;    // 邮件
	private Address address; // 
    private Person friend; // 朋友 
    
    @Override
    public Object clone() throws CloneNotSupportedException {
    	Person newp = new Person();
    	newp.name = new String(this.name);
    	newp.age = this.age;
    	newp.email = new String(this.email);
		newp.address = new Address(this.address.name, this.address.eCode);
        return newp;
    }
}

实现Serializable接口:

protected Son deepClone() throws IOException, ClassNotFoundException {
      Son son=null;
      //在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组中
      //默认创建一个大小为32的缓冲区
      ByteArrayOutputStream byOut=new ByteArrayOutputStream();
      //对象的序列化输出
      ObjectOutputStream outputStream=new ObjectOutputStream(byOut);//通过字节数组的方式进行传输
      outputStream.writeObject(this);  //将当前student对象写入字节数组中

      //在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区
      ByteArrayInputStream byIn=new ByteArrayInputStream(byOut.toByteArray()); //接收字节数组作为参数进行创建
      ObjectInputStream inputStream=new ObjectInputStream(byIn);
      son=(Son) inputStream.readObject(); //从字节数组中读取
      return son;
}
多层克隆

Cloneable接口方式可以实现深拷贝。但是有个问题,如果引用数量或者层数太多了怎么办呢?不可能去每个对象挨个写clone()吧?那怎么办呢?借助序列化!!!。

实现 Serializable 接口方式也可以实现深拷贝,而且这种方式还可以解决多层克隆的问题,多层克隆就是引用类型里面又有引用类型,层层嵌套下去。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/984818.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号