是将对象的状态信息转化为可以存储或者传输的形式的过程,一般将一个对象存储到一个储存媒介,例如档案或记忆体缓冲等,在网络传输过程中,可以是字节或者XML等格式;而字节或者XML格式的可以还原成完全相等的对象,这个相反的过程又称为反序列化;
我们可以通过多种方式来创建对象,并且只要对象没有被回收我们都可以复用此对象。但是,我们创建出来的这些对象都存在于JVM中的堆(stack)内存中,只有JVM处于运行状态的时候,这些对象才可能存在。一旦JVM停止,这些对象也就随之消失;
对象序列化,就是将对象中的信息
1.需要将对象信息持久化保存在硬盘中,如保存成文件 2.需要将对象信息在网络间传输, 3.需要将对象信息在后台服务间调用,如dubbo调用
UserModel.java
import java.io.Serializable; public class UserModel implements Serializable { // private static final long serialVersionUID = 8294180014912103005L; private String username; private String password; // private String age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // public static long getSerialVersionUID() { // return serialVersionUID; // } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // public String getAge() { // return age; // } // // public void setAge(String age) { // this.age = age; // } @Override public String toString() { return "UserModel{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }TransientTest.java
import org.yungu.config.model.UserModel; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; class TransientTest { public static void main(String[] args) { UserModel user = new UserModel(); user.setUsername("zhangsan"); user.setPassword("admin"); System.out.println("1。read before Serializable: "); System.out.println("2。username: " + user.getUsername()); System.err.println("3。password: " + user.getPassword()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("/Users/yzh/Documents/user.txt")); // 将User对象写进文件 os.writeObject(user); os.flush(); os.close(); ObjectInputStream is = new ObjectInputStream(new FileInputStream( "/Users/yzh/Documents/user.txt")); // 从流中读取User的数据 user = (UserModel) is.readObject(); is.close(); System.out.println("4。read after Serializable: "); System.out.println("5。username: " + user.getUsername()); System.err.println("6。password: " + user.getPassword()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }方法一序列化成功!
从控制台的打印结果来看,打印顺序并没有像预期的那样,按照1-6的顺序来执行。sys.err()打印的顺序是随机的。这点大家可以去百度下,看看原因。这里不做多的描述。
UserModel.java
import java.io.*; public class UserModel implements Externalizable { @Override public void writeExternal(ObjectOutput out) throws IOException { } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { } private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "UserModel{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }序列化不成功!
原因: Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。由于上面的代码中,并没有在这两个方法中定义序列化实现细节,所以输出的内容为空。还有一点值得注意:在使用Externalizable进行序列化的时候,在读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。所以,实现Externalizable接口的类必须要提供一个public的无参的构造器。
再次运行,结果: 方法二序列化成功!
UserModel.java
import java.io.*; public class UserModel implements Externalizable { @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(username); out.writeObject(password); out.writeObject(age); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { username = (String) in.readObject(); password = (String) in.readObject(); age = (String)in.readObject(); } private String username; private String password; private static String age = "18"; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public static String getAge() { return age; } public static void setAge(String age) { UserModel.age = age; } @Override public String toString() { return "UserModel{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", age='" + age + '\'' + '}'; } }TransientTest.java
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; class TransientTest { public static void main(String[] args) { UserModel user = new UserModel(); user.setUsername("zhangsan"); user.setPassword("admin"); System.out.println("1。read before Serializable: "); System.out.println(user.toString()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("/Users/yzh/Documents/user.txt")); // 将User对象写进文件 os.writeObject(user); os.flush(); os.close(); ObjectInputStream is = new ObjectInputStream(new FileInputStream( "/Users/yzh/Documents/user.txt")); // 从流中读取User的数据 user = (UserModel) is.readObject(); is.close(); System.out.println("4。read after Serializable: "); System.out.println(user.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }age被初始化进来了?验证一下
步骤:先初始化到本地文件中,再修改age的值,最后反序列化 a.注销反序列化的代码,只执行序列化 b.将age改为“16” c.执行反序列化
测试代码略,步骤同上: 结果:
分别测试了自动序列化和手动序列化两种情况: 测试结果:
UserModel.java
import java.io.*; public class UserModel implements Serializable { private String username; private transient String password; // private String age = "16"; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // public String getAge() { // return age; // } // // public void setAge(String age) { // this.age = age; // } @Override public String toString() { return "UserModel{" + "username='" + username + '\'' + ", password='" + password + '\'' + // ", age='" + age + '\'' + '}'; } }1.先序列化到本地文件 2.修改UserModel.java ,增加一个字段 3. 反序列化到本地 4.运行结果:
对象中没有显示声明版本id,当对象内容发生变化(新增,修改,删除),java会默认生成一个id;反序列化时,如果id不一致,就会报异常。
序列化的对象,都显示的声明一个版本id。