不要以为字段以transient修饰的话就一定不会被序列化

本文探讨了Java中transient关键字的作用及其实现细节,并通过ArrayList的序列化过程揭示了为何transient变量仍能被序列化的内在原因。此外,还介绍了自定义序列化的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

1: 先阅读这边文章:http://www.importnew.com/21517.html

 

2:被transient修饰真的会被序列化吗?

反例:java.util.ArrayList中底层存储数组就是transient,但是实际上还是可以被成功序列化。具体原因如下:

   transient Object[] elementData;

  

我的测试代码:

 

class ArrayListDemo implements Serializable {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> data = new ArrayList<>();
        data.add(1);
        data.add(1);
        data.add(1);
        data.add(1);

        ByteArrayOutputStream bo = new ByteArrayOutputStream();

        ObjectOutputStream out = new ObjectOutputStream(bo);
        out.writeObject(data);
        byte[] dataData = bo.toByteArray();

        FileOutputStream fo = new FileOutputStream("data.dat");
        fo.write(dataData);
        fo.close();

        FileInputStream fi = new FileInputStream("data.dat");
        ObjectInputStream in = new ObjectInputStream(fi);
        ArrayList<Integer> newList = (ArrayList<Integer>) in.readObject();
        System.out.println(newList.size());

        for (int i = 0; i < newList.size(); i++) {

            System.out.println(newList.get(i));

        }
    }
}  

输出:

数据还是成功序列化了,为什么会被序列化呢?分析原因还是需要看源码,就以java.io.ObjectOutputStream#writeObject写对象为入手点,跟踪源码会跟中到如下方法java.io.ObjectStreamClass#invokeWriteObject:

方法源码如下:

void invokeWriteObject(Object obj, ObjectOutputStream out)
        throws IOException, UnsupportedOperationException
    {
        requireInitialized();
        if (writeObjectMethod != null) {
            try {
                writeObjectMethod.invoke(obj, new Object[]{ out });
            } catch (InvocationTargetException ex) {
                Throwable th = ex.getTargetException();
                if (th instanceof IOException) {
                    throw (IOException) th;
                } else {
                    throwMiscException(th);
                }
            } catch (IllegalAccessException ex) {
                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {
            throw new UnsupportedOperationException();
        }
    }

  通过debug可以看到最终调用的是java.util.ArrayList#writeObject ,java.util.ArrayList#writeObject源码如下:

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }ke  

可以看出最终将elementData写出去了。反序列化同理不在分析。

 

重点来了,name为什么JDK需要这么做呢?原因如下:

JDK为什么不直接用elementData来序列化,而采用上诉的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。

 

 

小提示:

java.io.ObjectOutputStream#writeObject中的enableOverride字段可以自行实现writeObjectOverride方法,对于enableOverride=true需要通过实现ObjectOutputStream的子类实现自定义写对象。

转载于:https://www.cnblogs.com/leodaxin/p/9088741.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值