Java【基础版本】SerializationUtils#Clone浅拷贝、深拷贝

引入:今天工作中同事使用了Java8 Lists.partition 函数来批量更新/查询数据,架构组在mybatis插件扩展了mybatis#Interceptor 方法,具体实现拦截网上有大量资料可以查询下,这里就不引入介绍,连接器中使用 SerializationUtils.clone((Serializable) originParameter); 方法,来序列号param 对象,在对象复制的时候Lists.partition后得到的list 是一个Partition对象,该对象是继承了AbstractList 完成list 切分的。

我们看下Lists.partition源码:

 public static <T> List<List<T>> partition(List<T> list, int size) {
        Preconditions.checkNotNull(list);
        Preconditions.checkArgument(size > 0);
        return (List)(list instanceof RandomAccess ? new Lists.RandomAccessPartition(list, size) : new Lists.Partition(list, size));
    }
 private static class Partition<T> extends AbstractList<List<T>> {
        final List<T> list;
        final int size;

        Partition(List<T> list, int size) {
            this.list = list;
            this.size = size;
        }

        public List<T> get(int index) {
            Preconditions.checkElementIndex(index, this.size());
            int start = index * this.size;
            int end = Math.min(start + this.size, this.list.size());
            return this.list.subList(start, end);
        }

        public int size() {
            return IntMath.divide(this.list.size(), this.size, RoundingMode.CEILING);
        }

        public boolean isEmpty() {
            return this.list.isEmpty();
        }
    }

看下对象Partition list对象属于内部类,没实现implements Serializable接口导致序列号失败
错误提示:

Caused by: org.apache.commons.lang3.SerializationException: java.io.NotSerializableException: java.util.ArrayList$SubList
	at org.apache.commons.lang3.SerializationUtils.serialize(SerializationUtils.java:273) ~[commons-lang3-3.12.0.jar:3.12.0]
	at org.apache.commons.lang3.SerializationUtils.serialize(SerializationUtils.java:248) ~[commons-lang3-3.12.0.jar:3.12.0]
	at org.apache.commons.lang3.SerializationUtils.clone(SerializationUtils.java:138) ~[commons-lang3-3.12.0.jar:3.12.0]
	at com.txxy.cloud.starter.druid.interceptor.CipherInterceptor.intercept(CipherInterceptor.java:92) ~[txxy-cloud-starter-druid-1.8.0-SNAPSHOT.jar:1.8.0-SNAPSHOT]
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.5.5.jar:3.5.5]
	at com.sun.proxy.$Proxy466.update(Unknown Source) ~[?:?]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) ~[mybatis-3.5.5.jar:3.5.5]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) ~[mybatis-3.5.5.jar:3.5.5]
	at sun.reflect.GeneratedMethodAccessor1471.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.5.jar:2.0.5]

正文:

浅复制

浅层复制: 被复制的对象的所有成员属性都有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

换言之,浅层复制仅仅复制所考虑的对象(对象属性、数据),而不复制它所引用的对象(对象地址)。

深复制

深层复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。

换言之,深层复制要复制的对象引用的对象(对象属性、数据)都复制一遍。

2.深拷贝实现起来也比较简单,只需要对对象中的对象再次进行clone操作:

commons-lang-2.6.jar

例如:Object obj = SerializationUtils.clone( objectFrom )

源码:

   /**
     * <p>Deep clone an {@code Object} using serialization.</p>
     *
     * <p>This is many times slower than writing clone methods by hand
     * on all objects in your object graph. However, for complex object
     * graphs, or for those that don't support deep cloning this can
     * be a simple alternative implementation. Of course all the objects
     * must be {@code Serializable}.</p>
     *
     * @param <T> the type of the object involved
     * @param object  the {@code Serializable} object to clone
     * @return the cloned object
     * @throws SerializationException (runtime) if the serialization fails
     */
    public static <T extends Serializable> T clone(final T object) {
        if (object == null) {
            return null;
        }
        final byte[] objectData = serialize(object);
        final ByteArrayInputStream bais = new ByteArrayInputStream(objectData);

        try (ClassLoaderAwareObjectInputStream in = new ClassLoaderAwareObjectInputStream(bais,
                object.getClass().getClassLoader())) {
            /*
             * when we serialize and deserialize an object,
             * it is reasonable to assume the deserialized object
             * is of the same type as the original serialized object
             */
            @SuppressWarnings("unchecked") // see above
            final T readObject = (T) in.readObject();
            return readObject;

        } catch (final ClassNotFoundException ex) {
            throw new SerializationException("ClassNotFoundException while reading cloned object data", ex);
        } catch (final IOException ex) {
            throw new SerializationException("IOException while reading or closing cloned object data", ex);
        }
    }

笔记就介绍这里了~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟-要努力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值