赋值 直接  = ,克隆 clone

假如说你想复制一个简单变量。很简单:

int a= 5;
int b= a; b = 6; 这样 a == 5, b == 6

不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。

但是如果你复制的是一个对象、list集合的情况下,情况就有些复杂了。

class Student {
private int number; public int getNumber() {
return number;
} public void setNumber(int number) {
this.number = number;
} }
public class Test { public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1; System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
}
} 结果: 学生1:12345
学生2:12345

这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?

原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,

这样,stu1和stu2指向内存堆中同一个对象。如图:

要做到 赋值的两个对象之间的内存地址重新定义

实现对象克隆有两种方式:

  1). 实现Cloneable接口并重写Object类中的clone()方法;

class Address implements Cloneable {
private String add; public String getAdd() {
return add;
} public void setAdd(String add) {
this.add = add;
} @Override
public Object clone() { // 下面 这个是重点
Address addr = null;
try{
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
}

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

public class Outer implements Serializable{
private static final long serialVersionUID = 369285298572941L; //最好是显式声明ID
public Inner inner;
 //Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化] 
public Outer myclone() {
Outer outer = null;
try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
      // 将流序列化成对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
outer = (Outer) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return outer;
}
}

实现对象克隆有两种方式:

  1). 实现Cloneable接口并重写Object类中的clone()方法;

  2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

注: 集合的clone,ArrayList 默认实现了cloneable,但是List<A> A对象不是深度克隆,A对象的内容也是使用同一个内存地址,所以A对象也必须实现clone

Java的赋值、浅克隆和深度克隆的区别的更多相关文章

  1. 原型模式 —— Java的赋值、浅克隆和深度克隆的区别

    赋值 直接  = ,克隆 clone 假如说你想复制一个简单变量.很简单: int a= 5; int b= a; b = 6; 这样 a == 5, b == 6 不仅仅是int类型,其它七种原始数 ...

  2. 如何复制一个java对象(浅克隆与深度克隆)

    在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...

  3. Java clone() 浅克隆与深度克隆(转)

    以下文字转自:桔子园 http://www.blogjava.net/orangelizq/archive/2007/10/17/153573.html 现在Clone已经不是一个新鲜词语了,伴随着“ ...

  4. Java clone() 浅克隆与深度克隆

    内容转自:http://www.blogjava.net/orangelizq/archive/2007/10/17/153573.html 现在Clone已经不是一个新鲜词语了,伴随着“多莉”的产生 ...

  5. Cloneable接口的作用与深度克隆与浅度克隆

    cloneable接口的作用 cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则 ...

  6. Java中深度克隆和浅度克隆

    一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中 ...

  7. java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)

    java中传值及引伸深度克隆的思考 大家都知道java中没有指针.难道java真的没有指针吗?句柄是什么?变量地址在哪里?没有地址的话简直不可想象! java中内存的分配方式有两种,一种是在堆中分配, ...

  8. Java List的深度克隆

    关于java List的深度克隆 List是java容器中最常用的顺序存储数据结构之一.有些时候我们将一组数据取出放到一个List对象中,但是可能会很多处程序要读取他或者是修改他.尤其是并发处理的话, ...

  9. java对象 深度克隆(不实现Cloneable接口)和浅度克隆

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...

随机推荐

  1. google protobuf VC下的使用笔记

    1 使用protobuf 2.x 下载地址(3.x 在c++11 vs2017下报错) 源码 https://github.com/google/protobuf 或者直接下载 二进制文件 2 如果下 ...

  2. cpp 区块链模拟示例(一)工程建立

    /* 作 者: itdef 欢迎转帖 请保持文本完整并注明出处 技术博客 http://www.cnblogs.com/itdef/ 技术交流群 群号码:432336863欢迎c c++ window ...

  3. activeMq-3 Spring整合activeMq

    与jdbcTemplate相似的是,Spring也提供了JmsTemplate 生产者使用JmsTemplate生产消息,消费者实现一个监听器用于获取消息 项目用maven构建,jdk1.8, 文末提 ...

  4. Django 载入静态文件地址

    1,Django框架中有专门存放静态文件的目录. 项目中的CSS.图片.js都是静态文件 配置静态文件 在settings 文件中定义静态内容 2,这些静态文件,他们统一存放在项目目录,templat ...

  5. Linux学习---条件预处理的应用

    预处理的使用: ⑴包含头文件 #include ⑵宏定义 #define    替换,不进行语法检查 ①常量宏定义:#define 宏名 (宏体) (加括号为防止不进行语法检查而出现的错误) eg:# ...

  6. JDK源码核心包

    一.核心包有哪些? Jdk的包中,除开了lang包下面的类,用得最多的应该要属于util包下面的类了, 本篇文章主要针对Jdk的util包下面的类(util目录下面的类,暂时不包括util 包下面的子 ...

  7. 03-jQuery动画效果

    Query提供的一组网页中常见的动画效果,这些动画是标准的.有规律的效果:同时还提供给我们了自定义动画的功能. 显示动画 方式一: $("div").show(); 解释:无参数, ...

  8. segmentController

    xml <view class="segmentedControl">     <!-- 循环遍历 -->     <block wx:for=&qu ...

  9. MongoDB、MySQL

    我的电脑的系统Path:   D:\sqlite;D:\Program Files\MongoDB\Server\3.4\bin;%MYSQL_HOME%\bin;D:\Program Files\B ...

  10. Android-Java-构造方法内存图

    描述Dog对象: package android.java.oop07; // 描述Dog对象/实体 public class Dog { private String name; private i ...