Java序列化


1.序列化的定义

         把对象转化为字节序列的过程称为对象的序列化。

把字节序列恢复为对象的过程称为独享的反序列化。

2.序列化的作用

          主要用途有两种:

        1、把对象的字节序列永久的保存到硬盘上。

        2、在网络上传输对象的字节序列。

3.JDK序列化API

         java.io.ObjectOutputStream代表对象输出流,它的writeObject(Objectobj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

对象序列化的步骤:

1、创建一个对象输出流

2、通过writeObject()方法写入对象

对象反序列化的步骤:

1、创建一个对象输入流

2、通过readObject()方法读取对象

对象序列化的例子:

/**

 * 序列化测试

 * @author SN22010

 */

public classSerializableTest {

  

   @Ignore

   @Test

   public void testSerialize() throws FileNotFoundException,IOException {

      PersonTestperson = newPersonTest("liushuai", "123456");

     

      System.out.println("Before Serialize:");

      System.out.println(person.toString());

      ObjectOutputStreamos = newObjectOutputStream(new FileOutputStream(new File("D:/Person.txt")));

      os.writeObject(person);

      System.out.println("对象序列化成功!");

      os.close();

   }

  

   @Test

   public void testReadSerialize() throws FileNotFoundException,IOException, ClassNotFoundException {

      ObjectInputStreamis = newObjectInputStream(new FileInputStream(new File("D:/Person.txt")));

     

      System.out.println("反序列化前:");

      PersonTestperson = (PersonTest)is.readObject();

      System.out.println(person.toString());

   }

}

 

执行结果:

反序列化前:

PersonTest [username=liushuai,password=123456]

 

其中PersonTest为:

public classPersonTest implementsSerializable{

 

   private static final long serialVersionUID= 1L;

  

   private String username;

  

   private String password;

 

   public PersonTest() {

   }

 

   public PersonTest(Stringusername, String password) {

      super();

      this.username = username;

      this.password = password;

   }

 

   public String getUsername() {

      return username;

   }

 

   public void setUsername(Stringusername) {

      this.username = username;

   }

 

   public String getPassword() {

      return password;

   }

 

   public void setPassword(Stringpassword) {

      this.password = password;

   }

 

   @Override

   public String toString() {

      StringBuilderbuilder = newStringBuilder();

      builder.append("PersonTest [username=");

      builder.append(username);

      builder.append(", password=");

      builder.append(password);

      builder.append("]");

      return builder.toString();

   }

}

4. serialVersionUID的作用

          serialVersionUID的作用主要是序列化后添加一个字段或者方法,可以正常反序列化。例如:PersonTest中添加一条属性sex,执行反序列化结果为:

反序列化后:

PersonTest [username=liushuai,password=123456, sex=null]

这种是类中包含serialVersionUID的情况;当去掉serialVersionUID后执行结果为:

java.io.InvalidClassException:javaprojectTest.javaIO.PersonTest; local class incompatible: stream classdescserialVersionUID = 1, local class serialVersionUID = 8864783882401198096

   atjava.io.ObjectStreamClass.initNonProxy(Unknown Source)

   atjava.io.ObjectInputStream.readNonProxyDesc(Unknown Source)

   atjava.io.ObjectInputStream.readClassDesc(Unknown Source)

   atjava.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

   atjava.io.ObjectInputStream.readObject0(Unknown Source)

   atjava.io.ObjectInputStream.readObject(Unknown Source)

   atjavaprojectTest.javaIO.SerializableTest.testReadSerialize(SerializableTest.java:38)

   atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

   atsun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

   atsun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

   atjava.lang.reflect.Method.invoke(Unknown Source)

   atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)

   atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

   atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)

   atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

   atorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)

   atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)

   atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)

   atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)

   atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)

   atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)

   atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)

   atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)

   atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)

   atorg.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

   atorg.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

   atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

   atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

   atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

   atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

 

报错内容为:字符流中的serialVersionUID为1;而类中的serialVersionUID为: 8864783882401198096因而报错。

出现serialVersionUID=8864783882401198096的原因是在本地类中没有指定固定的序列号,java在编译时编译器会生成一条Uid。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。这样也可以避免上方错误。

5. transient关键字作用

         Transient可以加在类中某个字段之前,这样可以避免此字段序列化。例如:

private transientString sex;反序列化后执行结果为:

    PersonTest [username=liushuai, password=123456, sex=null]

6. Externalizable

         此接口是Serializable的拓展,在接口中存在两个方法: readExternal与writeExternal;

这两种方法可以确定哪些字段可以被序列化,哪些不需要,在这个接口下transient不起作用,例子如下:

   @Override

   public voidreadExternal(ObjectInput in) throws IOException,

         ClassNotFoundException{

      this.sex = (String)in.readObject();

      this.username =(String)in.readObject();

   }

 

   @Override

public void writeExternal(ObjectOutput out) throws IOException {

      out.writeObject(this.sex);

      out.writeObject(this.username);

   }

这两个属性是按照顺序赋值的。执行结果如下:

   PersonTest[username=刘帅, password=null, sex=男]

参考

         博客:

http://www.cnblogs.com/dukc/p/4817822.html;

http://www.cnblogs.com/xdp-gacl/p/3777987.html

http://www.cnblogs.com/lanxuezaipiao/p/3369962.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值