2种方法实现java对象的深拷贝
1、如果一个类没有实现Cloneable接口,直接调用clone()方法,会报异常CloneNotSupportedException,这一点已经在Object源码中写道:
- * @return a clone of this instance.
- * @exception CloneNotSupportedException if the object's class does not
- * support the {@code Cloneable} interface. Subclasses
- * that override the {@code clone} method can also
- * throw this exception to indicate that an instance cannot
- * be cloned.
- * @see java.lang.Cloneable
- */
- protected native Object clone() throws CloneNotSupportedException;
而且,源码也写到Object的clone()方法是浅拷贝的,这一点在之前的Object源码分析中我已经写过了.
2、自定义类实现深拷贝方法有2种,下面依次给出具体写法。
2.1、自定义类要实现Cloneable接口,并覆写clone()方法。
- /**
- * 深拷贝和浅拷贝的测试
- */
- //测试类1
- class Person implements Cloneable{
- String name;
- int age;
- Person(String name,int age){
- this.name=name;
- this.age=age;
- }
- @Override
- public Object clone() {
- try{
- return super.clone();
- }catch(CloneNotSupportedException e){
- return null;
- }
- }
- }
- //测试类2
- class Animal implements Cloneable{
- Person host;//主人
- int age;//年纪
- Animal(Person person,int age){
- this.host=person;
- this.age=age;
- }
- @Override
- public Object clone(){
- try{
- Animal animal=(Animal) super.clone();
- animal.host=(Person)host.clone();//深拷贝处理
- return animal;
- }catch (CloneNotSupportedException e){
- return null;
- }
- }
- }
- //测试
- public class Main{
- public static void main(String[] args) {
- Person person1=new Person("cxh",26);
- Person person2=(Person)person1.clone();
- System.out.println("----------------浅拷贝--------------");
- //测试Object的clone方法为浅拷贝
- //String类用==测试内存地址是否一致
- System.out.println("person1和person2的name内存地址是否相同:"+(person1.name==person2.name));
- System.out.println("----------------深拷贝--------------");
- //重写Object的clone方法,实现深拷贝
- //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝
- Animal animal1=new Animal(new Person("cxh",26),3);
- Animal animal2=(Animal) animal1.clone();
- System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));
- }
- }
输出:
- ----------------浅拷贝--------------
- person1和person2的name内存地址是否相同:true
- ----------------深拷贝--------------
- animal1和animal2的host内存地址是否相同:false
- Process finished with exit code 0
一个讲解很详细的博客:http://blog.csdn.net/zhangjg_blog/article/details/18369201
2.2、通过序列化方式实现深拷贝:先将要拷贝对象写入到内存中的字节流中,然后再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,那么这个新对象和原对象就不存在任何地址上的共享,自然实现了深拷贝。
自定义类需要实现Serializable接口。
- import java.io.*;
- /**
- * 深拷贝和浅拷贝的测试
- * 如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中,再从字节流中将其读出来,
- * 这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。
- */
- //工具类
- class CloneUtil{
- public static <T extends Serializable> T clone(T obj){
- T cloneObj=null;
- try{
- //写入字节流
- ByteArrayOutputStream baos=new ByteArrayOutputStream();
- ObjectOutputStream oos=new ObjectOutputStream(baos);
- oos.writeObject(obj);
- oos.close();
- //分配内存,写入原始对象,生成新对象
- ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());//获取上面的输出字节流
- ObjectInputStream ois=new ObjectInputStream(bais);
- //返回生成的新对象
- cloneObj=(T)ois.readObject();
- ois.close();
- }catch (Exception e){
- e.printStackTrace();
- }
- return cloneObj;
- }
- }
- //测试类1
- class Person implements Serializable{
- String name;
- int age;
- Person(String name,int age){
- this.name=name;
- this.age=age;
- }
- }
- //测试类2
- class Animal implements Serializable{
- Person host;//主人
- int age;//年纪
- Animal(Person person,int age){
- this.host=person;
- this.age=age;
- }
- }
- //测试
- public class Main{
- public static void main(String[] args) {
- System.out.println("----------------深拷贝--------------");
- //重写Object的clone方法,实现深拷贝
- //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝
- Animal animal1=new Animal(new Person("cxh",26),3);
- Animal animal2=CloneUtil.clone(animal1);
- System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));
- }
- }
输出结果:
- ----------------深拷贝--------------
- animal1和animal2的host内存地址是否相同:false
2种方法实现java对象的深拷贝的更多相关文章
- JAVA写JSON的三种方法,java对象转json数据
JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...
- 两个变量交换的四种方法(Java) 七种方法(JS)
两个变量交换的四种方法(Java) 对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) 1 class TestEV 2 ...
- 三种方法获取Class对象的区别
有关反射的内容见 java反射 得到某个类的Class对象有三种方法: 使用“类名.class”取得 Class.forName(String className) 通过该类实例对象的getClass ...
- 两个变量交换的四种方法(Java)
对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) class TestEV //创建一个类 { public static ...
- Hibernate,Session方法使得java对象进入持久化状态;持久化对象特征
以下情况java对象进入持久化状态: session.save()方法把临时对象转变为持久化对象. session.load()和session.get()方法得到的对象总是处于持久化状态. sess ...
- 数组k平移三种方法(java)
上代码,本文用了三种方法实现,时间复杂度不一样,空间复杂度都是o(1): public class ArrayKMove { /** * 问题:数组的向左k平移,k小于数组长度 * @param ar ...
- 五种方法实现Java的Singleton单例模式
面试的时候经常会问到Java的单例模式,这道题能很好的考察候选人对知识点的理解程度.单例模式要求在系统运行时,只存在唯一的一个实例对象. 下面我们来详细剖析一下其中的关键知识点,并介绍五种实现方法,以 ...
- Top k问题的讨论(三种方法的java实现及适用范围)
在很多的笔试和面试中,喜欢考察Top K.下面从自身的经验给出三种实现方式及实用范围. 合并法 这种方法适用于几个数组有序的情况,来求Top k.时间复杂度为O(k*m).(m:为数组的个数).具体实 ...
- 三种方法实现java调用Restful接口
1,基本介绍 Restful接口的调用,前端一般使用ajax调用,后端可以使用的方法比较多, 本次介绍三种: 1.HttpURLConnection实现 2.HttpClient实现 3.Spring ...
随机推荐
- HDU 5813 Elegant Construction ——(拓扑排序,构造)
可以直接见这个博客:http://blog.csdn.net/black_miracle/article/details/52164974. 对其中的几点作一些解释: 1.这个方法我们对队列中取出的元 ...
- SSH端口转发详解
正文 一.SSH端口转发简介 SSH会自动加密和解密所有SSH客户端与服务端之间的网络数据.但是,SSH还能够将其他TCP端口的网络数据通SSH链接来转发,并且自动提供了相应的加密及解密服务.这一过程 ...
- JAVA中随机生成确定范围内的随机数
最近工作中的一个业务需要再确定范围内取出一个随机数,网上到时搜出来一堆可以实现的方法,但是鄙人仍是理解不了,虽说已经copy方法直接完成工作了.今天抽时间整理下,希望能够帮助大家更好的理解随机数的实现 ...
- ceph-----常用命令
#查看存储池 ceph osd lspools #设置存储池副本数 ceph osd pool set data size 3 #查看存储池具体信息 ceph osd pool ls detail # ...
- Mac 配置adb环境变量(为了开Appium)亲测
1.启动终端Terminal. 2.进入当前用户的home目录. 在命令行输入echo $HOME 3.创建.bash_profile文件. 命令行输入touch .bash_profile 4.打开 ...
- StringUtils字符串工具类左侧补齐(leftPad)、右侧补齐(rightPad)、左右两侧补齐(center)工具方法
这里使用的是 org.apache.commons.lang.StringUtils;下面是StringUtils工具类中字符串左侧补齐的方法,示例如下: //左侧补齐 第一个参数:原始字符串,第二个 ...
- Centos7 Devstack [Rocky] 重启后无法联网
部署devstack-rocky版本后网络,可以 Ping 通自己的 IP,但 Ping 不同网关,ping不通同网段主机,查看网卡和ovs信息如下 解决 第一步 按造网上教程,修改br-ex,ens ...
- Selenium 2自动化测试实战29(组织单元测试用例和discover更多测试用例)
一.组织单元测试用例 看看unittest单元测试框架是如何扩展和组织新增的测试用例以之前的calculator.py文件为例,为其扩展sub()方法,用来计算两个数相减的结果. #coding:ut ...
- 八十三:redis之redis的字符串、过期时间、列表操作
字符串操作 设置值 set key value 设置有空格的值,加引号 set username 'hello world' 获取值 get key 删除值:del key 清除所有内容:flusha ...
- 查看自身公网ip的命令
curl ifconfig.me curl cip.cc curl ipinfo.io