美文网首页Java高级进阶
Java------List的深拷贝与浅拷贝

Java------List的深拷贝与浅拷贝

作者: Albert0211 | 来源:发表于2020-08-09 23:14 被阅读0次
    0.jpg

    Java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。

    浅拷贝(Shallow Copy)

    1、对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。

    2、对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

    深拷贝 (Deep Copy)

    相对于浅拷贝而言,对于引用类型的修改,并不会影响到对应的copy对象的值。

    最近项目中用到ArrayList,对于ArrayList的怎么实现拷贝,尤其是里边存放复杂对象,该怎么处理?
    怎么判断两个集合相等,存放的是稍微复杂的对象,非字符串String? 方法很多,比如:

    /**
     * 判断两个集合是否相等
     */
      public static boolean isCagoryEqual(List<Category> src, List<Category> dest) {
    
            if (src.size() != dest.size()) {
                return false;
            }
            for (Category fo : src) {
              
                if (!dest.contains(fo)) {
                    return false;
                }
               
     
            }
    
            return true;
        }
    

    这样,好像还不够,如何判断里边的对象是否相等呢?
    请允许我来一段kotlin代码,为什么重写equals,hashCode?

    class  Category() : Serializable {
        var id: String = ""
        var name: String = ""
        var priority: Int = 0
        var restaurantId: String = ""
        var isChecked: MutableList<Int> = ArrayList<Int>()
        private val serialVersionUID = 1L
    
        override fun equals(other: Any?): Boolean {
            if (other is FoodCategory) {
                val foodCategory = other as FoodCategory
                return this.id.equals(foodCategory.id) && this.name.equals(foodCategory.name)
            }
    
            return super.equals(other)
        }
    
        override fun hashCode(): Int {
            var result = id.hashCode()
            result = 31 * result + name.hashCode()
            return result
        }
    }
    

    需求是两个list不相等,则要使用原来的数据,显示界面,所以要深拷贝原来的list数据。直接贴代码:

     public static <E> List<E> copy(List<E> src) {
            try {
                ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(byteOut);
                out.writeObject(src);
    
                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
                ObjectInputStream in = new ObjectInputStream(byteIn);
                @SuppressWarnings("unchecked")
                List<E> dest = (List<E>) in.readObject();
                return dest;
            } catch (Exception e) {
                e.printStackTrace();
                return new ArrayList<E>();
            }
        }
    

    如果新旧list数据不一样,撤销新编辑的数据,怎么处理呢?

                    newList.clear()
                    for (i in 0 until oldList.size) {
                        val category = Category()
                        category.name = oldList[i].name
                        category.id = oldList[i].id
                        category.restaurantId = oldList[i].restaurantId
                    
                        ...
                       
                        newList.add(category)
                    }
    
    

    总结:

    1、Java对对象和基本的数据类型的处理是不一样的。在Java中用对象的作为入口参数的传递则缺省为”引用传递”,也就是说仅仅传递了对象的一个”引用”。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。 除了在函数传值的时候是”引用传递”,在任何用”=”向对象变量赋值的时候都是”引用传递”。

    2、 将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。

    相关文章

      网友评论

        本文标题:Java------List的深拷贝与浅拷贝

        本文链接:https://www.haomeiwen.com/subject/dbnrdktx.html