序列化粒度的控制

1 什么是序列化?
将对象以二进制的形式保存在内存,文件,网络中. 主要用于网络传输,写入文件,以及RPC(不同进程之间的调用).
序列化只保存成员变量的值,不保存静态变量.
2 什么是反序列化?
将内存,文件,网络中的二进制读取为对象.
3 如何实现序列化?
实现Serializable接口或者子类Externalizable
4 序列化的id的生成
序列化时自动生成序列化id号
一个实体类在不实现Serializable接口时,在写入文件或内存中时,也是要经过序列化的,此时系统会根据该实体类的类名,变量名,方法名自动生成一个序列化的id号.
在该实体类的对象写入文件中时,也携带了此序列化id的信息.当反序列化时,系统会先比对实体类的序列化id与写入文件中的id是否一致.相同则可以反序列化为该实体类的对象.
如该实体类后续有属性的增加,则系统序列化id号发生变化,此时进行反序列化时,由于id号不匹配,因此不能反序列化成功.
序列化时指定id号
实现相关的接口生成固定的id号,包含的其他对象也需要生成固定的序列化id号
5 如何实现对象序列化时的粒度的控制?
5.1 如何实现实体类中只有一个属性不序列化?
在属性上使用transient修饰
主要是通过在实体类中增加一个方法writeObject()其中调用defaultWriteObject()会进行默认的序列化操作(即被transient修饰的属性将不会被序列化),该实体类在序列化时会自动调用writeObject()方法.
1 在序列化之前对部分属性进行加密处理.
private void writeObject(ObjectOutputStream out) throws IOException {
//假如对象中包含password
password +=1;  
        out.defaultWriteObject();  
    }  
    反序列化时调用readObject()调用defaultReadObject()方法.
    1 反序列化之后对部分属性进行解码
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {  
        in.defaultReadObject(); 
        password -=1; 
        }


如果需要对使用transient修饰的属性进行序列化,可以在以上的两个方法中添加writeXXX()方法,反序列化时添加readXXX()方法实现.
private void writeObject(ObjectOutputStream out) throws IOException {  
        out.defaultWriteObject();  
        out.writeInt(age);  
    }  
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {  
        in.defaultReadObject();  
        age = in.readInt();  
        }
        
5.2 如何实现实体类中只有一个属性进行序列化?
实现Serializable接口的子接口externalizable接口.实现接口中的writeExternal()方法与readExternal()的方法,可以指定某一个属性的序列化,此时writeObject(),readObject()方法将失效
/**对象序列化时调用*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(ip);
}
/**对象反序列化调用*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
ip=in.readUTF();
}

注:该种方式会使用空构造方法创建对象,而且必须是public的,并将反序列化的对象的值填充到新new的对象中,实现Serializable接口就不会调用构造方法。

                此处参考:https://blog.csdn.net/bigtree_3721/article/details/50513295

                - 对Serializable对象反序列化时,由于Serializable对象完全以它存储的二进制位为基础来构造,因此并不会调用任何构造函数,因此Serializable类无需默认构造函数,但是当Serializable类的父类没有实现Serializable接口时,反序列化过程会调用父类的默认构造函数,因此该父类必需有默认构造函数,否则会抛异常。
- 对Externalizable对象反序列化时,会先调用类的不带参数的构造方法,这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出java.io.InvalidException: no valid constructor异常,因此Externalizable对象必须有默认构造函数,而且必需是public的.

6.防序列化破解单例
private Object readResolve() throws ObjectStreamException {  
        return InstanceHolder.instatnce;  
    }  
    实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。
    注:防反射破解单例,在构造方法中添加对象为空判断
    if(instatnce!=null){
    throws new RuntimeException("**");
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值