zoukankan      html  css  js  c++  java
  • 序列化和反序列化

    什么是java的序列化和反序列化

    java序列化就是把java对象转换为字节序列的过程。对于transient和static修饰的属性不会被序列化。原因:transient的作用就是这样,static是因为序列化作用的是对象,static修饰后是属于类的,所以没用。

    java反序列化就是把字节序列转换为java对象的过程。

    为什么要序列化

    很多应用中,需要对对象进行序列化,让它们离开内存,放入到硬盘中去,以便长期保存。比如session,当有10万用户并发访问,可能出现10万个session对象,内存可能吃不消,web容器会把一些session序列化到硬盘中,

    需要用的时候,再还原回来。

    序列化需要实现java.io.Serializable接口,序列化的时候有一个serialVersionUID参数,java序列化机制是通过运行时判断类的serialVersionUID来验证版本一致性。在进行反序列化,Java虚拟机会把传过来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的实体类,可以进行反序列化,否则Java虚拟机会拒绝对这个实体类进行反序列化并抛出异常。serialVersionUID有两种生成方式:

    1、默认的1L

    2、根据类名、接口名、成员方法以及属性等来生成一个64位的Hash字段

     如果实现java.io.Serializable接口的实体类没有显式定义一个名为serialVersionUID、类型为long的变量时,java的序列化机制会根据.class文件自动生成一个serialVersionUID,只要.class文件不变,那么变异多少次都是一样的。

     对象如果要序列化必须实现Serializable接口,如果该类中引用了别的实例变量,引用的类型也必须要实现该接口,如果没有实现是会出错的(如果值是null不会报错)。

    手动指定序列化过程

    如果进行序列化、反序列化时,虚拟机会首先试图调用待序列化对象里的writeObject和readObject方法,进行自定义的序列化和反序列化。如果在对象中没有定义,那么会默认调用的是ObjectOutputStream的defaultWriteObject和ObjectInputStream的defaultReadObject方法。

    public static void main(String[] args) throws Exception
    	{
    	    File file = new File("/home/tp/s.txt");
    	    OutputStream os = new FileOutputStream(file);  
    	    ObjectOutputStream oos = new ObjectOutputStream(os);
    	    oos.writeObject(new SerializableObject("str0", "str1"));
    	    oos.close();
    	        
    	    InputStream is = new FileInputStream(file);
    	    ObjectInputStream ois = new ObjectInputStream(is);
    	    SerializableObject so = (SerializableObject)ois.readObject();
    	    System.out.println("str0 = " + so.getStr0());
    	    System.out.println("str1 = " + so.getStr1());
    	    ois.close();
    	} 
    
    package algorithm;
    
    import java.io.Serializable;
    
    public class SerializableObject implements Serializable{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private String str0;
        private transient String str1;
        private static String str2 = "abc";
        
        public SerializableObject(String str0, String str1)
        {
            this.str0 = str0;
            this.str1 = str1;
        }
        
        public String getStr0()
        {
            return str0;
        }
    
        public String getStr1()
        {
            return str1;
        }
        
        private void writeObject(java.io.ObjectOutputStream s) throws Exception
        {
            System.out.println("我想自己控制序列化的过程");
            s.defaultWriteObject();
            s.writeInt(str1.length());
            for (int i = 0; i < str1.length(); i++)
                s.writeChar(str1.charAt(i));
        }
        
        private void readObject(java.io.ObjectInputStream s) throws Exception
        {
            System.out.println("我想自己控制反序列化的过程");
            s.defaultReadObject();
            int length = s.readInt();
            char[] cs = new char[length];
            for (int i = 0; i < length; i++)
                cs[i] = s.readChar();
            str1 = new String(cs, 0, length);
        }
    }
    

    在对象中写writeObject和readObject的通常用法:先通过defaultWriteObject和defaultReadObject方法序列化和反序列化对象。在文件结尾追加需要额外序列化的内容/读取额外的内容。

    为什么需要我们自己去序列化对象:因为使用默认的序列化并不安全,有的时候一些敏感的东西我们需要再次加密,这个时候就可以使用自己定义的writeObject和readObject方法来进行序列化和反序列化。具体做法,把需要再次加密的属性用transient字段修饰,然后自己去序列化它们。

    使用java原生的序列化方式来表示对象的优缺点

    1、纯粹的Java环境下这种方式可以很好地工作,因为它是Java自带的,也不需要第三方的Jar包的支持。

    2、多语言环境下,使用Java序列化方式进行存储后,很难用其他语言还原出结果

    3、占用的字节数比较大,而且序列化、反序列化效率也不高

    对象表示有各种各样的方式,序列化只是其中的一种而已。也可以把对象xml化以及json化。

    借鉴http://www.cnblogs.com/xrq730/p/4823684.html

  • 相关阅读:
    线段树(segment tree)
    外排序
    【机器学习】如何成为当下合格的算法工程师
    Result Maps collection already contains value for
    负向零宽断言
    正则匹配中 ^ $ 和  的区别
    jq异步上传文件(转载)
    js触发按钮点击事件
    ./ ,../ , 以及/的区别
    eclipse遇到不会部署的情况
  • 原文地址:https://www.cnblogs.com/tp123/p/6387603.html
Copyright © 2011-2022 走看看