1.序列化的概念:
序列化 :(Serialization)是將對象的狀態信息轉換爲可以存儲或傳輸的形式的過程【百度百科】
咋一看,專業術語發懵!!
2.序列化的理解:
問1:爲什麼序列化,要將對象的狀態信息轉換爲可以“存儲或者傳輸”的形式?
答1:計算機保存的數據是二級制數據(0和1),也就是數字
問2:那麼。如何將“對象的狀態信息”的信息狀態“轉化二級制數據”?
答2:如果要將“文本,圖片,視頻等信息儲存在電腦中,就需要序列化(也就是將文本,圖片,視頻等信息轉化爲二進制數據,保存在電腦中)”
3.舉個例子:
序列化的過程,其實在java IO流中就已經有體會了!!
例子1:
之前接觸的序列化,將文本信息存到電腦的:D:\test.txt
/**
* 將文本寫入磁盤
*/
public class Test {
public static void main(String[] args) throws Exception {
// 對於java代碼,是將信息輸出到磁盤中對應----> output流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");
// 寫入的內容
String text = "序列化";
// 將文本轉化爲字節byte,
byte[] bytes = text.getBytes();
// 將信息寫入磁盤
fileOutputStream.write(bytes);
// 關閉流
fileOutputStream.close();
}
}
// 在盤中,節能看到文件:test.txt
重點:String類型本身有getBytes()方法,將文本轉換爲字節碼
以上的過程,將文本信息轉化爲字節byte(轉化爲byte字節序列),然後流對象幫我們寫磁盤中
那麼反序列化呢?也就相當於我們讀取:test.txt中的信息
/**
* 讀取文本
* ASCII碼:一個英文字母(不分大小寫)佔一個字節的空間。一個二進制數字序列,在計算機中作爲一個數字單元,一般爲8位二進制數。換算爲十進制 ,最小值-128,最大值127。如一個ASCII碼就是一個字節。
* UTF-8編碼:一個英文字符等於一個字節,一箇中文(含繁體)等於三個字節。中文標點佔三個字節,英文標點佔一個字節
* Unicode編碼:一個英文等於兩個字節,一箇中文(含繁體)等於兩個字節。中文標點佔兩個字節,英文標點佔兩個字節
*/
public class Test {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
// 序列化是三個字,utf-8下,一個字符是三個字節,三個字是九個字節
byte[] bytes = new byte[9];
// 將D:\test.txt的信息轉化爲byte字節
int length = fileInputStream.read(bytes);
// 將字節轉化爲文本信息
String s = new String(bytes, 0, length);
System.out.println(s); // 輸出:序列化
}
}
例子2:
在玩遊戲的時候,你的信息(玩家暱稱,等級信息,玩家年齡等)往往存在電腦中,等你再玩該遊戲的時候,再將等級信息等讀取出來,那麼一個實體類,怎麼存到電腦中?
重點:自定義實體類,沒有getByte()方法,怎麼進行傳輸?
/**
* 將對象信息存儲到磁盤中
*/
public class Test {
public static void main(String[] args) throws Exception {
// 創建User實例
User user = new User("小白",3,99);
// 創建文件流對象
FileOutputStream fileOutputStream= new FileOutputStream("D:\\user.txt");
// 之前是通過對象.getBytes()方法,然後寫到流中,但User是我們自己創建的類,沒有該方法,用java提供的ObjectOutputStream對象流
// 將文件流對象給對象流
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
// 對象流將對象信息寫入D:\\user.txt中
outputStream.writeObject(user);
// 關閉流
outputStream.close();
fileOutputStream.close();
}
}
/**
* user類
*/
public class User {
private String name; // 用戶名稱
private int age; // 用戶年齡
private int level; // 遊戲等級
public User(String name, int age, int level) {
this.name = name;
this.age = age;
this.level = level;
}
public User() {
super();
}
// getter和setter省略
運行上面的程序:報錯!!
Exception in thread "main" java.io.NotSerializableException: serialization.User
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at serialization.Test.main(Test.java:17)
結果告訴我們,User類沒序列化!!!怎麼辦???Java中給我提供一個接口Serializable,源碼如下
public interface Serializable {
}
問:可是接口什麼都沒有啊,實現了有什麼用?
答:java讓你實現該接口,就爲了告訴程序,這個能序列化,你不實現,門都沒有!!相當於給實現的類一個通行證
實現一下:
/**
* user類
*/
public class User implements Serializable {
private String name; // 用戶名稱
private int age; // 用戶年齡
private int level; // 遊戲等級
public User(String name, int age, int level) {
this.name = name;
this.age = age;
this.level = level;
}
public User() {
super();
}
// getter和setter省略
運行程序,再去看:D:\user.txt文件的信息,這是什麼鬼?
我們可以用notepad++ 安裝HEX-Editor 查看十六進制(百度一下即可),內容如下:
怎麼看懂記事本中的內容?:
https://www.cnblogs.com/redcreen/articles/1955307.html
看不懂,不要緊,我們只是要將信息儲存在電腦中,目的已經達到了!!!
反序列化一下:
/**
* 讀取D:\\user.txt信息
*/
public class Test {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\user.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
User user = (User)objectInputStream.readObject();
System.out.println(user);
objectInputStream.close();
fileInputStream.close();
}
}
輸出:serialization.User@58372a00
得到的是一個對象的地址:那我們來toString(),看看他的廬山真面目:
/**
* user類
*/
public class User implements Serializable {
private String name;
private int age;
private int level;
public User(String name, int age, int level) {
this.name = name;
this.age = age;
this.level = level;
}
public User() {
super();
}
// getter和setter省略
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", level=" + level +
'}';
}
再次運行:
Exception in thread "main" java.io.InvalidClassException: serialization.User; local class incompatible: stream classdesc serialVersionUID = 4255073330490321173, local class serialVersionUID = -6139716091850480259
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at serialization.Test.main(Test.java:15)
serialVersionUID = 4255073330490321173;這個好像有點熟悉,是什麼呢?
報錯信息,序列化的id不一致!什麼意思?(User類的序列化id和磁盤文件D:\user.txt中的序列化id不一致),Serializable源碼註釋也有說明
看看該博客的解釋:https://blog.csdn.net/jediael_lu/article/details/26813153
我們給實體類,加上序列化id
/**
* user類
*/
public class User implements Serializable {
private static final long serialVersionUID = 4125096758372084309L;
private String name;
private int age;
private int level;
public User(String name, int age, int level) {
this.name = name;
this.age = age;
this.level = level;
}
public User() {
super();
}
// getter和setter省略
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", level=" + level +
'}';
}
要重新序列化生成D:\user.txt文件,再次反序列化:
輸出結果:User{name='小白', age=3, level=99}
好啦!!!
問:爲什麼序列化?
問:爲什麼實現Serializable?
問:還要加上private static final long serialVersionUID = 4125096758372084309L;
希望能對讀者有幫助!
其他:
IDEA實現序列化接口Serializable自動生成serialVersionUID
(idea2019位置:Setting->Editor->Inspections->Java->Serialization issues->Serializable class without ’serialVersionUID’)