java的浅拷贝和深拷贝

原型模式有两种实现方法,深拷贝和浅拷贝。浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象……而深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。

也就是说浅拷贝只复制一个对象,传递引用,不能复制实例。而深拷贝对对象内部的引用均复制,它是创建一个新的实例,并且复制实例。

假如有一个对象 Object o = new Object(),再声明一个Object o1;
如果o1要获得第一个对象,首先想到用 "="赋值,但是这个常常会和想要的不一样

class Man {
    private String sex;
    int age;

    public Man(String sex, int age) {
        this.sex = sex;
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Man{" +
                "sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}
浅拷贝
传递基本类型参数
public class Test {
 /**
     * 基本类型参数
     * @param m
     */
    public static void testBasicType(int m) {
        System.out.println("m=" + m);
        m = 100;
        System.out.println("m=" + m);
    }
    /**
     * 传递对象引用
     * @param m1
     */
    static void testObject(Man m1) {
        System.out.println(m1);
        Man d2 = m1;
        d2.setAge(45);
        System.out.println(m1);
    }

    /**
     * 在这里,s引用先指向传过来的对象,接着发生改变指向新创建的对象
     * @param s
     */
    public static void changeRef(StringBuilder s) {
        s = new StringBuilder("Java");
    }
    
    
    
  public static void main(String[] args) {
           /**
         * 基本类型参数
         */
        int i = 50;
        testBasicType(i);
        System.out.println(i);
        }

运行结果: 这里写图片描述
可以看到 变量 i的值 没有修改

传递 对象引用
1、
       /**
         * 传递对象 参数
         */
        Man d1 = new Man("hehe", 25);
        testObject(d1);
        System.out.println(d1);

这里写图片描述
局部方法改变了对象的属性 Copy

今天被这个问题搞得头都大了,一直用等于号赋值,今天发现一些莫名其妙的错误,看了好多文章才发现,原来对象赋值不能用等于号,等于只能用于主类型的赋值(String,int,float之类),而如果是其他的类生产的对象,用等于号是映射,并非赋值,只要改了等号一边的值,另一边的也跟着变化,就是说JAVA没有开辟新的内存,只是给原来的对象再起了个名字而已。

2、

/**
     * 在这里,引用  先指向传过来的对象,接着发生改变指向新创建的对象
     * @param s
     */
    public static void changeRef(StringBuilder s) {
        s = new StringBuilder("Java");
    }

      /**
         * 传递对象 参数
         */
        Man d1 = new Man("hehe", 25);
        testObject(d1);
        System.out.println(d1);

这里的值没发生改变

深拷贝

第一种方法:递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止。根据这个思路对之前的代码进行重构。重构之后的代码如下所示:

public class Demo {
  private HashMap<String, SearchWord> currentKeywords=new HashMap<>();
  private long lastUpdateTime = -1;

  public void refresh() {
    // Deep copy
    HashMap<String, SearchWord> newKeywords = new HashMap<>();
    for (HashMap.Entry<String, SearchWord> e : currentKeywords.entrySet()) {
      SearchWord searchWord = e.getValue();
      SearchWord newSearchWord = new SearchWord(
              searchWord.getKeyword(), searchWord.getCount(), searchWord.getLastUpdateTime());
      newKeywords.put(e.getKey(), newSearchWord);
    }

    // 从数据库中取出更新时间>lastUpdateTime的数据,放入到newKeywords中
    List<SearchWord> toBeUpdatedSearchWords = getSearchWords(lastUpdateTime);
    long maxNewUpdatedTime = lastUpdateTime;
    for (SearchWord searchWord : toBeUpdatedSearchWords) {
      if (searchWord.getLastUpdateTime() > maxNewUpdatedTime) {
        maxNewUpdatedTime = searchWord.getLastUpdateTime();
      }
      if (newKeywords.containsKey(searchWord.getKeyword())) {
        SearchWord oldSearchWord = newKeywords.get(searchWord.getKeyword());
        oldSearchWord.setCount(searchWord.getCount());
        oldSearchWord.setLastUpdateTime(searchWord.getLastUpdateTime());
      } else {
        newKeywords.put(searchWord.getKeyword(), searchWord);
      }
    }

    lastUpdateTime = maxNewUpdatedTime;
    currentKeywords = newKeywords;
  }

  private List<SearchWord> getSearchWords(long lastUpdateTime) {
    // TODO: 从数据库中取出更新时间>lastUpdateTime的数据
    return null;
  }
}

第二种方法:先将对象序列化,然后再反序列化成新的对象。具体的示例代码如下所示:

public Object deepCopy(Object object) {
  ByteArrayOutputStream bo = new ByteArrayOutputStream();
  ObjectOutputStream oo = new ObjectOutputStream(bo);
  oo.writeObject(object);
  
  ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
  ObjectInputStream oi = new ObjectInputStream(bi);
  
  return oi.readObject();
}

https://time.geekbang.org/column/article/200786

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值