`

深度克隆与浅度克隆

 
阅读更多

在java中,无法使 用类直接赋值,即使用Login loginB=loginA;这样的赋值方式,虽然编译起来是没有错的,但往往与实际用法出现叉错.本意是new 一个新类出来,将LoginA的值赋给LoginB,但是,这时候,你会发现,如果你修改了LoginB的值,loginA的值也会随之而改变,这是因为什么呢?

    其实这个原因很简单,因为java不同C语言类的有指针,java是通过直接指向内存的引用而调用对象的

如图:

 java对象类赋值
 
由图可以看出,对像LoginB仍然指向LoginA的堆空间
 
为了解决这种情况,我使用如下的例子:
先定义User类
public class User {
 private int id;
 private String userName;
 private String password;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 
}
再定义Login类
public class Login implements Cloneable {
 
 private int id;
 private String loginIp;
 private User loginUser;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getLoginIp() {
  return loginIp;
 }
 public void setLoginIp(String loginIp) {
  this.loginIp = loginIp;
 }
 public User getLoginUser() {
  return loginUser;
 }
 public void setLoginUser(User loginUser) {
  this.loginUser = loginUser;
 }
 
 public Object clone() {
  Login login=null;
  try {
   login = (Login) super.clone();
  } catch (CloneNotSupportedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return login;
 }
}
测试一:
public class Test {
 public static void main(String[] args) {
  Login loginA=new Login();
  loginA.setId(1000);
  User user = new User();
  user.setId(2000);
  loginA.setLoginUser(user);
  
  Login loginB=loginA;
  loginB.setId(1050);
  loginB.getLoginUser().setId(2050);
  
  System.out.println("loginA id:"+loginA.getId());
  System.out.println("user id:"+user.getId());
 }
}
输出结果:loginA id:1050
         user id:2050
 
测试二:将Test类中的Login loginB=loginA;
              改成:Login loginB=(Login) loginA.clone();
输出结果:loginA id:1000
         user id:2050
由这两个测试,可以看出,使用clone()赋值,与直接赋值的区别,在这里,可以看出Login中的User类的值,无论是使用clone()赋值还是 使用直接赋值,它里面的值都会随着LoginB的改变而改变,但改变LoginB其它内容的时候,LoginA中却不会产生变化,这种情况叫做浅度克隆
     浅度克隆只会将基础数据类型克隆出来,而深层的对像则不会被克隆出来;
     内存图如下:java对象类赋值
注:使用浅度克隆的类除了要重写Object类中的Clone()方法,还必须要实现 Cloneable接口,才可以合法地对该类实例进行按字段复制。
 
为了解决类中类不能被克隆的情况:所以产生了深度克隆
将创建Login类更改成如下:
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Login implements Serializable {
 
 private int id;
 private String loginIp;
 private User loginUser;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getLoginIp() {
  return loginIp;
 }
 public void setLoginIp(String loginIp) {
  this.loginIp = loginIp;
 }
 public User getLoginUser() {
  return loginUser;
 }
 public void setLoginUser(User loginUser) {
  this.loginUser = loginUser;
 }
 
 public Login clone(Login login) {
  Login newLogin=null;
   ByteArrayInputStream bin = null;  
         ByteArrayOutputStream bout = null;  
         try {  
             //把对象对到内存中去  
             bout = new ByteArrayOutputStream();  
             ObjectOutputStream oos = new ObjectOutputStream(bout);  
             oos.writeObject(login);  
             oos.close();  
             //把对象从内存中读出来            
             ByteArrayInputStream bais = new ByteArrayInputStream(bout.toByteArray());  
             ObjectInputStream ois = new ObjectInputStream(bais);  
             newLogin = (Login) ois.readObject();  
             ois.close();  
         } catch (IOException e) {  
             // TODO Auto-generated catch block  
             e.printStackTrace();  
         } catch (ClassNotFoundException e) {  
             // TODO Auto-generated catch block  
             e.printStackTrace();  
         }  
  return newLogin;
 }
 
}
 
 
同时User类也要实现Serializable 接口,目的是标识可序列化
 
测试三:将Test类中的:Login loginB=(Login) loginA.clone();
              改为: Login loginB=new Login().clone(loginA);
 
测试结果:loginA id:1000
         user id:2000
 
由此可以看出,loginB类中的任何值改变了,原赋值中的类的值是不会跟着改变的
内存变化:
java对象类赋值

分享到:
评论

相关推荐

    解析JAVA深度克隆与浅度克隆的区别详解

    Java提供了两种主要的克隆方式:浅度克隆(Shallow Clone)和深度克隆(Deep Clone)。理解这两种克隆的区别对于优化内存管理和复制复杂对象至关重要。 **浅度克隆(Shallow Clone)** 浅度克隆仅仅复制了对象本身...

    java-6个机制.doc

    **1.4 深度克隆与浅度克隆** - **浅度克隆**:仅复制对象的基本类型属性值,对于对象引用类型属性,只复制引用本身而非引用指向的对象。 - **深度克隆**:不仅复制对象本身,还递归复制对象内的所有引用对象。 **...

    c#深度复制浅度复制

    在C#编程中,"深度复制"和"浅度复制"是对象复制过程中两个重要的概念,它们涉及到如何正确地复制复杂的数据结构。了解并熟练掌握这两种复制方式对于编写高效、可靠的代码至关重要。 首先,让我们来定义这两个术语:...

    C#中深度复制和浅度复制详解

    在C#编程中,了解深度复制和浅度复制的概念至关重要,因为它们直接影响到对象的复制行为,特别是当处理包含复杂数据结构的对象时。本文将详细解释这两种复制方式,并通过一个实例来展示它们的区别。 首先,让我们...

    ASP.NET深度复制和浅度复制分析

    深度复制则创建了嵌套对象的独立副本,复制的对象与原始对象之间不存在任何引用共享。 在使用这两种复制方式时,开发者需要根据实际情况来选择,深度复制虽然能保证对象间完全独立,但代价是更高的资源消耗和处理...

    javascript克隆对象深度介绍

    在进行对象克隆的过程中,根据复制的深度,可以分为浅度克隆和深度克隆。 浅度克隆(Shallow Clone)仅适用于对象的第一层属性,如果属性值为基本类型,则复制其值;如果属性值为引用类型,则复制其引用地址。这...

    prototypeAndCreate.zip

    在“prototypeAndCreate.zip”压缩包中,我们可能找到与原型模式相关的代码示例,包括浅度克隆和深度克隆两种不同的复制策略。浅度克隆仅仅复制对象本身,而不复制其引用的对象,而深度克隆则会递归地复制对象及其...

    网络语言浅度研究报告.doc

    网络语言浅度研究报告.doc

    基于java实现浅度爬虫应用

    浅度爬虫是相对于深度爬虫而言的,它主要集中在网站表面的页面,通常用于获取网页的元数据或者对特定领域的信息进行快速索引。本项目基于Java编程语言,为初学者提供了一个简单的入门实践,旨在帮助理解如何构建一个...

    浅度探索C++对象模型bin3.ppt

    浅度探索C++对象模型bin3.ppt

    MyEclipse浅度优化方法

    ### MyEclipse浅度优化方法 #### 一、引言 在软件开发过程中,开发工具的性能直接影响到工作效率。MyEclipse作为一款流行的Java集成开发环境(IDE),因其丰富的功能和良好的用户界面受到广泛欢迎。然而,对于一些...

    浅度解析C++运算符重载

    本文将浅度解析C++中的运算符重载,以帮助初学者更好地理解和应用这一机制。 1. 概述 运算符重载是C++中的一种多态形式,它使得我们可以为不同的数据类型定义相同运算符的不同行为。通过重载,我们可以让自定义...

    初中数学深度学习:从理解到实践.pdf

    深度学习与浅度学习相对,后者通常表现出机械记忆、僵化理解和生硬应用。 2. 初中数学深度学习的重要性:在初中数学教学中,深度学习有助于学生利用已有经验,通过理论梳理和经验提纯,使学习更加深入和有效。 3. ...

    Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍

    如果希望复制的对象与原始对象完全独立,不希望修改副本会影响原始对象,那么应该选择深拷贝。相反,如果只需要简单的表面拷贝,且不关心引用字段指向的对象,那么浅拷贝就足够了。 总的来说,Java中的深拷贝和浅...

    深度学习视域下智能化评价系统的构建路径.pdf

    为了更好地理解深度学习的内涵,我们需明确深度学习与浅度学习的区别。深度学习者具备深度理解知识的能力,能够将新旧知识有机结合起来,并在新环境中灵活运用。而浅度学习者则主要依靠记忆应对考试,无法将知识转化...

    实例详解vue.js浅度监听和深度监听及watch用法

    Vue提供了一个非常实用的功能,即对数据变化的侦听机制,其中包括浅度监听和深度监听。此外,Vue还提供了一个特殊的选项——watch,用来侦听和响应Vue实例上的数据变动。 首先,我们来看浅度监听,它通常指的是Vue...

Global site tag (gtag.js) - Google Analytics