1. 程式人生 > >java transient關鍵字

java transient關鍵字

java物件在實現了Serilizable介面後這個物件就可以被序列化,但是java的這種序列化機制會將這個類的所有屬性和方法都序列化.有時候我們的一些敏感資訊比如密碼並不想序列化傳輸給對方,這個時候transient關鍵字就派上用場了,如果一個類的變數加上了transient關鍵字那麼這個欄位就不會被序列化

下面這個例子我們利用transient避免User序列化過程中密碼欄位的序列化

@Data
@ToString
@AllArgsConstructor
public class User implements Serializable {
    private String username;
    private
transient String password; }

我們首先建立一個物件User,利用ObjectOutputStream序列化到本地檔案,利用ObjectInputStream讀取並反序列化為User物件

try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt"));
     ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) {
    User user = new
User("jack", "123456"); System.out.println(user); os.writeObject(user); os.flush(); user = (User) is.readObject(); System.out.println(user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }

執行結果如下

User{username='jack'
, password='123456'}
User{username='jack', password='null'}

可以看到密碼欄位為空

從上面這個例子可以看到一旦變數被transient關鍵字修飾,該變數就不參與持久化過程,再進一步深入學習transient
1. transient關鍵字只能修飾變數,不能修飾方法和類.如果變數型別是我們自定義的類,那麼這個類需要實現Serializable介面
2. 靜態變數無論是否被transient關鍵字修飾都不參與序列化

接下來我們詳細講解下上述的第二點
我們給User新增一個欄位Country,這是一個靜態欄位

我們重試上面的過程

try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt"));
     ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) {
    User user = new User("jack", "123456");
    User.setCountry("China");
    System.out.println(user);
    os.writeObject(user);
    os.flush();
    user = (User) is.readObject();
    System.out.println(user);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

與第一個例子不同點在於我們在利用setter設定Country
執行結果

User{username='jack', password='123456', country='China'}
User{username='jack', password='null', country='China'}

我們發現country好像被序列化了,但是靜態變數無論如何都不參與初始化的,我們猜想country中的值是jvm中的而不是反序列化出來的
我們利用下面這個例子驗證我們的猜想

try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt"));
     ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) {
    User user = new User("jack", "123456");
    User.setCountry("China");
    System.out.println(user);
    os.writeObject(user);
    os.flush();
    User.setCountry("American");
    user = (User) is.readObject();
    System.out.println(user);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

物件序列化寫入檔案後我們再修改User的country欄位為American
結果如下

User{username='jack', password='123456', country='China'}
User{username='jack', password='null', country='American'}

可以看到country果然變成了American我們的猜想成立,也就是說反序列化後static型變數的值為JVM中的值

還有一點關於transient關鍵字失靈的情況需要注意,看下面這個例子

@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Externalizable {
    private transient String username;
    private transient int age;
    private transient String fatherName;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(username);
        out.writeInt(age);
        out.writeObject(fatherName);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        username = (String) in.readObject();
        age = in.readInt();
        fatherName= (String) in.readObject();
    }
}

student學生類實現了Externalizable介面作用我們下面再講,student的所有屬性都使用transient關鍵字修飾

測試程式碼如下

try (ObjectInput in = new ObjectInputStream(new FileInputStream(new File("student.txt")));
     ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("student.txt")));) {
    Student student = new Student("student", 20, "father");
    System.out.println(student);
    out.writeObject(student);
    out.flush();
    student = (Student) in.readObject();
    System.out.println(student);
} catch (Exception e) {
    e.printStackTrace();
}

執行結果如下所示

Student(username=student, age=20, fatherName=father)
Student(username=student, age=20, fatherName=father)

可以看到儘管transient關鍵字修飾了所有屬性,按理這些屬性都不應該被序列化,這是為什麼呢,這要談到java的序列化機制了,java自帶的物件的序列化可以通過兩種方法實現,一種就是Serializable,另外一種就是上面的Externalizable,利用External自定義java序列化方式,選擇序列化哪些屬性都與transient關鍵字無關了