Java 为什么需要拷贝对象

3 篇文章 0 订阅
1 篇文章 0 订阅

学习java过程中我一直以为,拷贝没什么用
直到自己在编程时遇到了一个问题才发现拷贝的作用
我一直以为的拷贝方式

//引用拷贝
    private static void copyReferenceObject(){
        Person p = new Person(23, "zhang");
        Person p1 = p;
        System.out.println(p);
        System.out.println(p1);
    }

这是引用拷贝
这里打印的结果:
Person@3654919e
Person@3654919e
可以看到,打印的结果是一样的,也就是说,二者的引用是同一个对象,并没有创建出一个新的对象。因此要区分引用拷贝和对象拷贝的区别。
也因此问题来了
我在JDBC编程时读取数据库的内容赋值给对象n`

N n=new N();
while(JDBC.resultSet.next()) {
        			
    		    	n.Priority=JDBC.resultSet.getString("priority");   //权限
    				n.date=JDBC.resultSet.getString("date");    //note
    				n.todo_text=JDBC.resultSet.getString("todo");
        			items.add(n);   //这里items是一个arraylist
        			count++;
        		}

我每次将n加入表中,下一次又改变了n的成员变量的值
那么最后n的值为数据库表中最后一行的值
表中虽然加了好多n
但他们实际上是一个
指向同一内存空间
最后打印出来的结果会有多行数据库中最后一行的重复值

解决方案:
自然而然的我想到了拷贝,很遗憾初次修改我使用了引用拷贝
还是一块内存空间
浅拷贝
如果pojo中存在的是基本数据类型 ,String 除外 ,实现Cloneable 覆写Clone 方法 这个就是浅拷贝

package core.java.deeporshoawcopy;

/**
 * @author DGW-PC
 * @date 2018年6月7日
 * @see 验证   浅拷贝  一般要求实体类使用包装类型 对于深拷贝 类中存在对其他类的引用,也需要实现cloneable接口
 */

class Person implements Cloneable{
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException  {
        /*Person p=null;
        try{
            p=(Person) super.clone();
        }catch (CloneNotSupportedException e) {
        }*/
        return super.clone();
    }
}

public class Base {
    
     public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setName("a");
        person.setAge(12);
        Person per1=(Person) person.clone();
        per1.setName("b");
        per1.setAge(14);;
        System.out.println(person.getName()+" "+person.getAge().hashCode(0));
        System.out.println(per1.getName()+" "+per1.getAge());
    }

}

内存图:

在这里插入图片描述

深拷贝

  • 如果你的POJO 存在的不是基本上数据类型,可以是自己定义类型,也可以其他包提供的类型 这里以java 提供的Data 的为例子 可以看下面的代码 自身实现clone 方法 你在涉及到使用拷贝的时候一定要注意别的包提供的类是否出现了问题
/**
     * Return a copy of this object.
     */
    public Object clone() {
        Date d = null;
        try {
            d = (Date)super.clone();
            if (cdate != null) {
                d.cdate = (BaseCalendar.Date) cdate.clone();
            }
        } catch (CloneNotSupportedException e) {} // Won't happen
        return d;
    }
  • 下面介绍一下基本深拷贝的代码 很短 : 你一定主要 主类包装了多少其他的引用类型的其他类,那么其他必须都要实现Cloneable 接口 以及clone (保护方法) 方法

方法原型:

仔细一看,它还是一个 native 方法,大家都知道 native 方法是非 Java 语言实现的代码,供 Java 程序调用的,

因为 Java 程序是运行在 JVM 虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现

复制代码

1/*
2Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
3The general intent is that, for any object x, the expression:
41) x.clone() != x will be true
52) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
63) x.clone().equals(x) will be true, this is not an absolute requirement.
7*/
8protected native Object clone() throws CloneNotSupportedException;

需要满足的条件:

对于任何对象x,表达式:

1)x.clone()!= x将为真
2)x.clone()。getClass()== x.getClass()为true,但这不是绝对要求。
3)x.clone()。equals(x)将为true,这不是绝对要求。

具体代码:

package core.java.deeporshoawcopy;


/**
 * @author DGW-PC
 * @date 2018年6月7日
 * @see 实现序列化  深拷贝
 */

class Dog implements Cloneable{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class User implements Cloneable{
    private String name;
    private Dog dog;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Dog getDog() {
        return dog;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        User u=(User) super.clone();
        u.dog=(Dog) dog.clone(); //多个需要在全部把关系搞清楚
        return u;
    }
}

public class ObjCloner {
        public static void main(String[] args) throws CloneNotSupportedException {
            Dog dog = new Dog();
            dog.setName("田园犬");
            User user = new User();
            user.setDog(dog);
            user.setName("王二");
            User user1=(User) user.clone();
            user1.setName("张三");
            Dog dog2 = new Dog();
            dog2.setName("德国牧羊犬");
            user1.setDog(dog2);
            System.out.println(user.getName()+"养了"+ user.getDog().getName());
            System.out.println(user1.getName()+"养了"+ user1.getDog().getName());
        }
}

总结:

在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。
(如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。)
实现对象克隆有两种方式:

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

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

DLC:不使用拷贝的话我上面提出的问题可以在循环体中每次新实例化出一个对象n来解决
While(JDBC.resultSet.next()){
N n=new N();

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值