深入探索Java对象的序列化

简介:
对象序列化就是把对象写入到输出流中,用来存储或者传输。
对象的反序列化就是从输入流中读取对象。
要序列化的对象应该实现Serializable接口。
Serializable接口是一个标识接口,没有抽象方法。
Serializable有一个子接口Externalizable,实现Externalizable接口的类可以自行控制对象序列化荷反序列化过程。
一般来说,没有必要自己实现序列化接口,直接交给Java虚拟机是上策。
实现了序列化接口的类,如果其成员不需要序列化进去,则使用transient关键字进行修饰。
 
下面给出个例子:
import java.io.*; 

/** 
* Java对象的序列化测试 
* File: ObjectStreamTest.java 
* User: leizhimin 
* Date: 2008-3-12 20:41:43 
*/
 
public  class ObjectStreamTest { 
     public  static  void main(String args[]) { 
        testObjectSeri(); 
        testObjectInSeri(); 

    } 

     /** 
     * 对象序列化测试 
     */
 
     public  static  void testObjectSeri() { 
        Person person =  new Person( "熔岩""341022225562156""lavasoft"); 
        FileOutputStream fos =  null
        ObjectOutputStream oos =  null
         try { 
            fos =  new FileOutputStream( "Q:\\study\\java5study\\src\\io\\person.dat"); 
            oos =  new ObjectOutputStream(fos); 
            oos.writeObject(person); 
        }  catch (FileNotFoundException e) { 
            System.out.println( "找不到指定的文件!"); 
            e.printStackTrace(); 
        }  catch (IOException e) { 
            e.printStackTrace(); 
        }  finally { 
             try { 
                oos.flush(); 
                oos.close(); 
            }  catch (IOException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

     /** 
     * 对象反序列化测试 
     */
 
     public  static  void testObjectInSeri() { 
        FileInputStream fis =  null
        ObjectInputStream ois =  null
        Person person =  null
         try { 
            fis =  new FileInputStream( "Q:\\study\\java5study\\src\\io\\person.dat"); 
            ois =  new ObjectInputStream(fis); 
            person = (Person) ois.readObject(); 
        }  catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        }  catch (IOException e) { 
            e.printStackTrace(); 
        }  catch (ClassNotFoundException e) { 
            e.printStackTrace(); 
        }  finally { 
             try { 
                ois.close(); 
            }  catch (IOException e) { 
                e.printStackTrace(); 
            } 
        } 

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


/** 
* 测试序列化所用的类 
*/
 
class Person  implements Serializable { 
     private String username; 
     private String cardNumber; 
     private  transient String password; 

     public Person(String username, String cardNumber, String password) { 
         this.username = username; 
         this.cardNumber = cardNumber; 
         this.password = password; 
    } 

     public String getUsername() { 
         return username; 
    } 

     public  void setUsername(String username) { 
         this.username = username; 
    } 

     public String getCardNumber() { 
         return cardNumber; 
    } 

     public  void setCardNumber(String cardNumber) { 
         this.cardNumber = cardNumber; 
    } 

     public String getPassword() { 
         return password; 
    } 

     public  void setPassword(String password) { 
         this.password = password; 
    } 

     public String toString() { 
        StringBuffer sb =  new StringBuffer( this.getClass().getName()); 
        sb.append( "["); 
        sb.append( "\n\t"); 
        sb.append( "username=" +  this.username); 
        sb.append( "\n\t"); 
        sb.append( "cardNumber=" +  this.cardNumber); 
        sb.append( "\n\t"); 
        sb.append( "password=" +  this.password); 
        sb.append( "]"); 
         return sb.toString(); 
    } 
}
 
运行结果为:
io.Person[ 
    username=熔岩 
    cardNumber=341022225562156 
    password= null

Process finished with exit code 0 
 
属性password=null,说明在序列化过程中忽略了。
 
说到此,还有一个容易忽略的问题--serialVersionUID :
 
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致  InvalidClassException 。可序列化类可以通过声明名为  "serialVersionUID"  的字段(该字段必须是静态 (static)、最终 (final) 的  long  型字段)显式声明其自己的 serialVersionUID:
 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
 
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过, 强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的  InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用  private 修改器显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于立即声明类 -- serialVersionUID 字段作为继承成员没有用处。
 
serialVersionUID 在Eclipse里可以自动生成,可是在其他大部分IDE工具里面都不能自动生成。但是这个long型值取多少,心里没底,与其写还不如不写。
 

本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/65542,如需转载请自行联系原作者
相关文章
|
1月前
|
JSON Java API
GSON 泛型对象反序列化解决方案
GSON 泛型对象反序列化解决方案
C4.
|
1月前
|
缓存 Java
Java的Integer对象
Java的Integer对象
C4.
13 0
|
26天前
|
Java
java8中List对象转另一个List对象
java8中List对象转另一个List对象
37 0
|
2天前
|
Java
Java基础之对象的引用
Java基础之对象的引用
5 0
|
6天前
|
Java
Java中如何克隆一个对象?
【4月更文挑战第13天】
15 0
|
7天前
|
Java API 数据库
深入解析:使用JPA进行Java对象关系映射的实践与应用
【4月更文挑战第17天】Java Persistence API (JPA) 是Java EE中的ORM规范,简化数据库操作,让开发者以面向对象方式处理数据,提高效率和代码可读性。它定义了Java对象与数据库表的映射,通过@Entity等注解标记实体类,如User类映射到users表。JPA提供持久化上下文和EntityManager,管理对象生命周期,支持Criteria API和JPQL进行数据库查询。同时,JPA包含事务管理功能,保证数据一致性。使用JPA能降低开发复杂性,但需根据项目需求灵活应用,结合框架如Spring Data JPA,进一步提升开发便捷性。
|
11天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
18 5
|
12天前
|
存储 Java 编译器
对象的交响曲:深入理解Java面向对象的绝妙之处
对象的交响曲:深入理解Java面向对象的绝妙之处
46 0
对象的交响曲:深入理解Java面向对象的绝妙之处
|
17天前
|
Java
在Java中,多态性允许不同类的对象对同一消息做出响应
【4月更文挑战第7天】在Java中,多态性允许不同类的对象对同一消息做出响应
17 2
|
26天前
|
Java
Java常用封装Base对象
Java常用封装Base对象
8 0