摘要:是表明该数据不参与序列化。使用对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。有了这个标记的就能被序列化机制处理。
虽是读书笔记,但是如转载请注明出处 http://segmentfault.com/blog/exploring/
.. 拒绝伸手复制党
在阅读HashMap和TreeMap的源码过程中,发现了一个奇怪的事情: 这些类执行了Serializable接口,却在关键地方,比如hashmap将存储数据的table 数组声明为transient. 这是何意?
stackoverflow 查了一下,大概有两个原因。
1.transient 是表明该数据不参与序列化。因为 HashMap 中的存储数据的数组数据成员中,数组还有很多的空间没有被使用,没有被使用到的空间被序列化没有意义。所以需要手动使用 writeObject() 方法,只序列化实际存储元素的数组。
2. 由于不同的虚拟机对于相同 hashCode 产生的 Code 值可能是不一样的,如果你使用默认的序列化,那么反序列化后,元素的位置和之前的是保持一致的,可是由于 hashCode 的值不一样了,那么定位函数 indexFor()返回的元素下标就会不同,这样不是我们所想要的结果.
对象 ----- 字节流 ----- 文件
什么是对象序列化:
Java 平台允许我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM 的生命周期更长。但在现实应用中,就可能要求在 JVM 停止运行之后能够保存 (持久化) 指定的对象,并在将来重新读取被保存的对象。Java 对象序列化就能够帮助我们实现该功能。 使用 Java 对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的 "状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。 除了在持久化对象时会用到对象序列化之外,当使用 RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。 一个对象能够序列化的前提是实现`Serializable`接口, `Serializable` 接口没有方法,更像是个标记。有了这个标记的 Class 就能被序列化机制处理。使用 `ObjectInputStream` 和 `ObjectOutputStream` 进行对象的读写。
class User implements Serializable{ private static final long serialVersionUID = 201322060620L; private String username; private transient String passwd; public String getUsername(){ return username; } public void setUsername(String username){ this.username = username; } public String getPasswd(){ return this.passwd; } public void setPasswd(String passwd){ this.passwd = passwd; } } public class TransientTest { public static void main(String[] args) { // TODO Auto-generated method stub User user = new User(); user.setUsername("GSM"); user.setPasswd("1010"); System.out.println("read before Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); try{ ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("F:/user.txt")); os.writeObject(user);//将User对象写入文件 os.flush(); os.close(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } try { ObjectInputStream is = new ObjectInputStream( new FileInputStream( "F:/user.txt")); user = (User) is.readObject(); // 从流中读取User的数据 is.close(); System.out.println(" read after Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
user.txt 即 user对象保存到文件的内容是二进制的串,16进制查看:
文件一共63B
想更一进步的支持我,请扫描下方的二维码,你懂的~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/64308.html
摘要:简介是的线程安全版本,内部也是通过数组实现,每次对数组的修改都完全拷贝一份新的数组来修改,修改完了再替换掉老数组,这样保证了只阻塞写操作,不阻塞读操作,实现读写分离。 简介 CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过数组实现,每次对数组的修改都完全拷贝一份新的数组来修改,修改完了再替换掉老数组,这样保证了只阻塞写操作,不阻塞读操作,实现读写...
摘要:删除元素作为双端队列,删除元素也有两种方式,一种是队列首删除元素,一种是队列尾删除元素。作为,又要支持中间删除元素,所以删除元素一个有三个方法,分别如下。在中间删除元素比较低效,首先要找到删除位置的节点,再修改前后指针,时间复杂度为。 介绍 LinkedList是一个以双向链表实现的List,它除了作为List使用,还可以作为队列或者栈来使用,它是怎么实现的呢?让我们一起来学习吧。 继...
摘要:加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行操作即重建内部数据结构,从而哈希表将具有大约两倍的桶数。成员变量每个对由封装,存在了对象数组中。 虽是读书笔记,但是如转载请注明出处 http://segmentfault.com/blog/exploring/ .. 拒绝伸手复制党 LinkedLis...
摘要:源码解析属性双向链表头节点双向链表尾节点是否按访问顺序排序双向链表的头节点,旧数据存在头节点。双向链表的尾节点,新数据存在尾节点。内部类位于中位于中存储节点,继承自的类,用于单链表存储于桶中,和用于双向链表存储所有元素。 简介 LinkedHashMap内部维护了一个双向链表,能保证元素按插入的顺序访问,也能以访问顺序访问,可以用来实现LRU缓存策略。 LinkedHashMap可以看...
摘要:源码分析默认容量默认容量为,也就是通过创建时的默认容量。集合中元素的个数真正存储元素的个数,而不是数组的长度。方法删除指定元素值的元素,时间复杂度为。方法求两个集合的交集。 简介 ArrayList是一种以数组实现的List,与数组相比,它具有动态扩展的能力,因此也可称之为动态数组。 继承体系 showImg(https://segmentfault.com/img/bVbv8Ow?w...
阅读 1093·2021-10-12 10:11
阅读 876·2019-08-30 15:53
阅读 2286·2019-08-30 14:15
阅读 2960·2019-08-30 14:09
阅读 1196·2019-08-29 17:24
阅读 971·2019-08-26 18:27
阅读 1282·2019-08-26 11:57
阅读 2145·2019-08-23 18:23