Java核心技术卷2 高级特性 学习笔记(2)

参考:Java核心技术卷2 高级特性 第二章

对象序列化是以特殊的文件格式存储对象数据的。当存储一个对象时,这个对象所属的类也必须存储。这个类的描述包含:

  • 类名
  • 序列化的版本唯一的ID,它是数据类型和方法签名的指纹
  • 描述序列化方法的标志集
  • 对数据域的描述

指纹是通过对类、超类、接口、域类型和方法签名按照规范方式排序,然后将安全散列算法(SHA)应用于这些数据而获得的。

SHA是一种可以为较大的信息快提供指纹的快速算法,不论是最初的数据块尺寸有多大,这种指纹总是20个字节的数据包。它是通过在数据上执行一个灵巧的操作序列而创建的,这个序列在本质上可以百分百地保证无论这些数据以何种方式发生变化,其指纹也都会跟着变化。但是序列化机制只使用了SHA码的前8个字节作为类的指纹。即便这样,当类的数据域或方法发生变化时,其指针跟着变化的可能性还是非常大。

了解确切的文件格式确实不那么重要,但是对象流对其所包含的所有对象都有详细描述,并且这些充足的细节可以用来重构对象和对象数组,因此了解它还是有很大益处的。

对象流输出中包含所有对象的类型和数据域,每个对象都被赋予一个序列号,相同对象的重复出现将被存储为对这个对象的序列号的引用。

某些数据域是不可以被序列化的,java有一种很简单的机制来防止这种域被序列化,就是将它们标记成是transient的。如果这些域属于不可序列化的类,也需要将它们标记成transient。瞬时的域在对象被序列化时总是被跳过的。

除了让序列化机制来保存和恢复对象数据,类还可以定义它自己的机制。为了做到这一点,这个类必须实现Externalize接口,需要它定义两个方法:

public void readExternal(ObjectInputStream in) throws IOException; ClassNotFoundException;
public void writeExternal(ObjectOutputStream out) throws IXException;

这些方法对包括超类数据在内的整个对象的存储和恢复负全责。

在写出对象时,序列化机制在输出流中仅仅只是记录该对象所属的类。在读入可外部化的类时,对象输入流将用无参构造器创建一个对象,然后调用readExternal方法。

在序列化和反序列化时,如果目标对象是唯一的,那么你必须加倍当心,这通常会在实现单例和类型安全的枚举时发生。

如果使用的是Java语言的enum接口,就不必担心序列化,它能够正常工作。

即使构造器是私有的,序列化机制也可以创建新的对象!

为了解决这个问题,必须定义称为readResolve的特殊序列化方法。如果定义了readResolve方法,在对象被序列化之后就会调用它。它必须返回一个对象,而该对象之后会称为readObject的返回值。

序列化机制有一种很有趣的用法:即提供了一种克隆对象的简便途径,只要对应的类是可序列化的即可。做法很简单,直接将对象序列化到输出流中,然后将其读回。这样产生的新对象是对现有对象的一个深拷贝。

内存映射文件

大多数操作系统都可以利用虚拟内存实现来将一个文件或者文件的一部分映射到内存中。然后这个文件就可以当做是内存数组一样地访问,比传统的文件操作要快的多。

java.nio包使内存映射变得简单,需要做的:

首先,从文件中获得一个通道(channel),通道是用于磁盘文件的一种抽象,它使我们可以访问诸如内存映射、文件加锁机制以及文件间快速数据传递等操作系统特性。

FileChannel channel=FileChannel.open(path, options);

然后,通过调用FileChannel类的map方法从这个通道中获得一个ByteBuffer。你可以指定想要映射的文件区域与映射模式,支持的模式有三种:

  • FileChannel.MapMode.READ_ONLY:所产生的缓冲区是只读的,任何对该缓冲区写入的尝试都会导致ReadOnlyBufferException异常。
  • FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的,任何修改都会在某个时刻写回到文件中。注意,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的确切行为是依赖于操作系统的。
  • FileChannel.MapMode.PRIVATE:所产生的缓冲区是可写的,但是任何修改对这个缓冲区来说都是私有的,不会传播到文件中。

一旦有了缓冲区,就可以使用ByteBuffer类和Buffer超类的方法读写数据了。

缓冲区支持顺序和随机数据访问,它有一个可以通过get和put操作来移动的位置。

在使用内存映射时,创建了单一的缓冲区横跨整个文件或者我们感兴趣的文件区域。还可以使用更多的缓冲区来读写大小适度的信息块。

缓冲区是由具有相同类型的数值构成的数组,Buffer类是一个抽象类,它有总多的具体子类,包括ByteBuffer、CharBuffer、DoubleBuffer、IntBuffer、LongBuffer和ShortBuffer。

实践中最常用到的是ByteBuffer和CharBuffer。每个缓冲区都具有:

  • 一个容量,它永远不能改变
  • 一个读写位置,下一个值将在此进行读写
  • 一个界限,超过它进行读写是没有意义的
  • 一个可选的标记,用于重复一个读入或写出的操作

这些值的关系:0<= 标记<=位置<=界限<=容量

文件加锁机制

多个同时执行的程序需要修改同一个文件时,这些程序需要以某种方式进行通信,不然文件很容易被破坏。文件锁可以解决这个问题,可以控制对文件或者文件中某个范围的字节的访问。

文件加锁机制是依赖于操作系统的,需要注意的几点:

  • 在某些系统中,文件加锁仅仅是建议性的,如果一个应用未能得到锁,它仍旧可以向被另一个应用并发锁定的文件执行写操作
  • 在某些系统中,不能再锁定一个文件的同事将其映射到内存中
  • 文件锁是由整个Java虚拟机持有的,如果有两个程序是由同一个虚拟机启动的,那么它们不可能每一个都获得在同一个文件上的锁,当调用lock和tryLock方法时,如果虚拟机已经在同一个文件上持有了另一个重叠锁,那么这两个方法将抛出OverlappingFileLockException
  • 在一些系统中,关闭一个通道会释放由java虚拟机持有的底层文件上的所有锁。因此,在同一个锁定文件上应避免使用多个通道。
  • 在网络文件系统上锁定文件时高度依赖于系统的,因此应该尽量避免

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值