java序列化:爲什麼序列化,爲什麼實現Serializable,serialVersionUID拿來幹嘛?

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’)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章