• Java 序列化Serializable具体解释(附具体样例)


                                                     Java 序列化Serializable具体解释(附具体样例) 

    1、什么是序列化和反序列化
    Serialization(序列化)是一种将对象以一连串的字节描写叙述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。


    2、什么情况下须要序列化 
    a)当你想把的内存中的对象保存到一个文件里或者数据库中时候。
    b)当你想用套接字在网络上传送对象的时候;
    c)当你想通过RMI传输对象的时候。


    3、怎样实现序列化

    将须要序列化的类实现Serializable接口就能够了。Serializable接口中没有不论什么方法,能够理解为一个标记,即表明这个类能够序列化。


    4、序列化和反序列化样例

    假设我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。

    这时候,仅仅须要调用writeObject()方法就能够将对象序列化。并将其发送给OutputStream记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构。而反序列的过程(即将一个序列还原成为一个对象),须要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()就可以。

    package com.sheepmu;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    public class MyTest implements Serializable
    {
    	private static final long serialVersionUID = 1L;
    	private String name="SheepMu";
    	private int age=24;
    	public static void main(String[] args)
    	{//以下代码实现序列化
    		try 
    		{
    			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名称为 my.out ;ObjectOutputStream能把Object输出成Byte流
    			MyTest myTest=new MyTest();
    			oos.writeObject(myTest); 
    			oos.flush();  //缓冲流 
    			oos.close(); //关闭流
    		} catch (FileNotFoundException e) 
    		{		 
    			e.printStackTrace();
    		} catch (IOException e) 
    		{
    			e.printStackTrace();
    		} 
    		fan();//调用以下的  反序列化  代码
    	}
    	public static void fan()//反序列的过程
    	{	 
             ObjectInputStream oin = null;//局部变量必需要初始化
    		try
    		{
    			oin = new ObjectInputStream(new FileInputStream("my.out"));
    		} catch (FileNotFoundException e1)
    		{		 
    			e1.printStackTrace();
    		} catch (IOException e1)
    		{
    			e1.printStackTrace();
    		}      
            MyTest mts = null;
    		try {
    			mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}     
             System.out.println("name="+mts.name);    
             System.out.println("age="+mts.age);    
    	}
    }
    会在此项目的工作空间生成一个 my.out文件。

    序列化后的内容稍后补齐。先看反序列化后输出例如以下:

    name=SheepMu
    age=24


    5、序列化ID

    序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不反复的 long 类型数据(实际上是使用 JDK 工具生成)。在这里有一个建议,假设没有特殊需求,就是用默认的 1L 就能够,这样能够确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因。由于不同的序列化id之间不能进行序列化和反序列化。


    6.序列化前和序列化后的对象的关系

    是 "=="还是equal? or  是浅复制还是深复制? 

    答案:深复制,反序列化还原后的对象地址与原来的的地址不同

    序列化前后对象的地址不同了,可是内容是一样的。并且对象中包括的引用也同样。

    换句话说,通过序列化操作,我们能够实现对不论什么可Serializable对象的”深度复制(deep copy)"——这意味着我们复制的是整个对象网。而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是同样,说明他们是同一个对象,可是与其它流的对象地址却不同样

    也就说,仅仅要将对象序列化到单一流中,就能够恢复出与我们写出时一样的对象网,并且仅仅要在同一流中。对象都是同一个。


    7.静态变量是否能序列化

    若把上面的代码中的 age变量前加上 static ,输出任然是

    name=SheepMu
    age=24

    可是看以下的样例:

    package com.sheepmu;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    public class MyTest implements Serializable
    {
    	private static final long serialVersionUID = 1L;
    	private String name="SheepMu";
    	private static int age=24;
    	public static void main(String[] args)
    	{//以下代码实现序列化
    		try 
    		{
    			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//输出流保存的文件名称为 my.out 。ObjectOutputStream能把Object输出成Byte流
    			MyTest myTest=new MyTest();
    			oos.writeObject(myTest); 
    			oos.flush();  //缓冲流 
    			oos.close(); //关闭流
    		} catch (FileNotFoundException e) 
    		{		 
    			e.printStackTrace();
    		} catch (IOException e) 
    		{
    			e.printStackTrace();
    		} 
    		fan();//调用以下的  反序列化  代码
    	}
    	public static void fan()
    	{
    		new MyTest().name="SheepMu_1";     //!!!!!!!!!!!!!!!!重点看这两行 更改部分
    		age=1;        //!!!!!!!!!!!!!!!!!!!重点看这两行 更改部分 
             ObjectInputStream oin = null;//局部变量必需要初始化
    		try
    		{
    			oin = new ObjectInputStream(new FileInputStream("my.out"));
    		} catch (FileNotFoundException e1)
    		{		 
    			e1.printStackTrace();
    		} catch (IOException e1)
    		{
    			e1.printStackTrace();
    		}      
            MyTest mts = null;
    		try {
    			mts = (MyTest ) oin.readObject();//由Object对象向下转型为MyTest对象
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}     
             System.out.println("name="+mts.name);    
             System.out.println("age="+mts.age);    
    	}
    }
    
    输出结果为:

    name=SheepMu
    age=1
    为何把最上面代码的age变量添上static 后还是反序列化出了24呢?而新的从新对变量赋值的代码,不是static的得到了序列化本身的值。而static的则得到的是从新附的值。原因: 序列化会忽略静态变量,即序列化不保存静态变量的状态。静态成员属于类级别的,所以不能序列化。即 序列化的是对象的状态不是类的状态。这里的不能序列化的意思。是序列化信息中不包括这个静态成员域。

    最上面加入了static后之所以还是输出24是由于该值是JVM载入该类时分配的值。

    注:transient后的变量也不能序列化可是情况稍复杂,稍后开篇说。

    8、总结:

    a)当一个父类实现序列化,子类自己主动实现序列化,不须要显式实现Serializable接口。

    b)当一个对象的实例变量引用其它对象,序列化该对象时也把引用对象进行序列化。

    c) static,transient后的变量不能被序列化;



     

  • 相关阅读:
    函数传参-修改文本
    函数传参-商品计价
    嵌套选项卡自动播放
    仿淘宝自动播放菜单栏
    仿淘宝侧边栏菜单
    图片自动切换
    定时器应用-页面弹出广告
    转:Java面试题集(1-50)
    转:115个Java面试题和答案——终极列表(上)
    毕向东day01笔记--dos-jdk-jre-环境变量等
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6852051.html
Copyright © 2020-2023  润新知