明天来讲讲序列化以及反序列化
Serializable 接口,没有 method,实现该接口表明能够序列化以及反序列化
ObjectOutputStream,将 Object 序列化为 stream 流
ObjectInputStream,通过 stream 流反序列化转化为 Object
序列化时,计算出一个 Serial version unique identifier 标识这个 class(平安的哈希值),并将这个哈希值其存储到 stream 中,而反序列化时 java 再次计算这个 class 的标识值(如果 class 类的定义已扭转则值也会发生变化),新计算的值与从 stream 取出来的值做比拟,如果不统一,示意该类的序列化版本与咱们领有的以后类定义不兼容。会产生 InvalidClassException。
public class BankAccount implements Serializable {
private String id;
private int balance = 0;
public BankAccount(String id){this.id = id;}
public BankAccount(String id, int startBalance){
this.id = id;
balance = startBalance;
}
public String getId(){return id;}
public synchronized int getBalance(){return balance;}
public synchronized void deposit(int amount){balance += amount;}
public synchronized void withdrawal(int amount){balance -= amount;}
}
序列化与反序列化办法
public class Main {public static void main(String[] args) {BankAccount ba = new BankAccount("10",500);
ba.deposit(250);
saveAccount(ba,"/Users/buxuesong/Documents/svn_code/demo/account.dat");
BankAccount bb = loadAccount("/Users/buxuesong/Documents/svn_code/demo/account.dat");
System.out.println(bb.getId() +"|" + bb.getBalance());
}
private static void saveAccount(BankAccount ba, String fileName){try(ObjectOutputStream os = new ObjectOutputStream(Files.newOutputStream(Paths.get(fileName)))){os.writeObject(ba);
}catch(Exception e){System.out.println(e.getSuppressed() +"|"+ e.getMessage());
}
}
private static BankAccount loadAccount(String fileName){
BankAccount ba = null;
try(ObjectInputStream oi = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)))){ba = (BankAccount) oi.readObject();}catch(Exception e){System.out.println(e.getSuppressed() +"|"+ e.getMessage());
}
return ba;
}
}
输入
10 | 750
当扭转了 class 的定义字段后,与原有序列化的惟一标识不同,导致无奈反序列化,这就须要自定义 serialVersionUID,当前批改了该类,也会能够反序列化回来,只是新增的字段默认值为空或者是原始默认值(int 的话就是 0)
private static final long serialVersionUID = -23324324324L;
还能够自定义序列化以及反序列化的办法,在 BankAccount 中
private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{ObjectInputStream.GetField fields = in.readFields();
id = (String) fields.get("id",null);
balance = fields.get("balance",0);
lastTxType = fields.get("lastTxType",'u');
lastTxAmount = fields.get("lastTxAmount",-1);
}
执行办法
BankAccount bb = loadAccount("/Users/buxuesong/Documents/svn_code/demo/account.dat");
System.out.println(bb.getId() +"|" + bb.getBalance()+"|" +bb.getLastTxType()+"|"+bb.getLastTxAmount());
输入
10 | 750 | u | -1
还能够针对某些字段不必须做序列化解决,须要通过 transient 润饰该字段,能够通过其它形式获取回来,这样节俭了序列化的工夫
具体如下
public class AccountGroup implements Serializable {
private static final long serialVersionUID = 106962907155393149L;
private Map<String, BankAccount> accountMap = new HashMap();
private transient int totalBalance;
public int getTotalBalance(){return totalBalance;}
public void addAccount(BankAccount account){totalBalance += account.getBalance();
accountMap.put(account.getId(), account);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();
for(BankAccount account: accountMap.values())
totalBalance += account.getBalance();}
}
执行办法中的存储到流以及从流中取回的办法
private static void saveGroup(AccountGroup g, String fileName){try(ObjectOutputStream os = new ObjectOutputStream(Files.newOutputStream(Paths.get(fileName)))){os.writeObject(g);
}catch(Exception e){System.out.println(e.getSuppressed() +"|"+ e.getMessage());
}
}
private static AccountGroup loadGroup(String fileName){
AccountGroup g = null;
try(ObjectInputStream oi = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)))){g = (AccountGroup) oi.readObject();}catch(Exception e){System.out.println(e.getSuppressed() +"|"+ e.getMessage());
}
return g;
}
执行办法:
BankAccount acct1 = new BankAccount("1234", 500);
BankAccount acct2 = new BankAccount("9866", 750);
AccountGroup group = new AccountGroup();
group.addAccount(acct1);
group.addAccount(acct2);
saveGroup(group, "/Users/buxuesong/Documents/svn_code/demo/group.dat");
AccountGroup group2 = loadGroup("/Users/buxuesong/Documents/svn_code/demo/group.dat");
System.out.println("group2.getTotalBalance:"+group2.getTotalBalance());
输入
group2.getTotalBalance:1250
其余序列化办法,实现 Externalizable 接口
void writeExternal(ObjectOutput out);
void readExternal(ObjectInput in);