transient关键字的一些注意点
一. transient关键字的概述:
在平常开发中,如果某个类实现了Serializable接口,则这个类就可以被序列化,然而如果某些属性,我们不想序列化,则我们可以使用transient关键字修饰,在序列化对象时,这些被transient修饰的属性就可以不被序列化。
二. transient关键字注意点:
1. transient关键字只能修饰属性,不能修饰方法跟类。如果该属性是我们自定义的类对象,则这个自定义的类需要实现Serializable接口。
2. static修饰的属性无论有没有transient修饰,均不能被序列化。(其实在平时开发中,你会发现序列化后在发序列化,static修饰的属性还是有值的,但是,这个值不是序列化得来的,而是JVM中对应的static变量的值)测试:
①有一个实体类User
class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4116444461933762681L;
private static String userName;
private transient String passwrod;
public User() {
super();
}
public User(String userName, String passwrod) {
super();
this.userName = userName;
this.passwrod = passwrod;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPasswrod() {
return passwrod;
}
public void setPasswrod(String passwrod) {
this.passwrod = passwrod;
}
}
②序列化的代码:
public static void testObjectOutputStream(User user) {
try(ObjectOutputStream outputStream =
new ObjectOutputStream(new FileOutputStream("xy.txt"))
) {
System.out.println("序列化之前:");
System.out.println("username: " + user.getUserName());
System.out.println("password: " + user.getPasswrod());
outputStream.writeObject(user);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
③反序列化的代码:
public static void testObjectInputStream() {
try(ObjectInputStream inputStream =
new ObjectInputStream(new FileInputStream("xy.txt"))) {
User user = new User();
user.setUserName("xxxx");
user = (User) inputStream.readObject();
System.out.println("反序列化后: ");
System.out.println("username: " + user.getUserName());
System.out.println("password: " + user.getPasswrod());
} catch(IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
④测试:
public static void main(String[] args) {
testObjectOutputStream(new User("xuy", "1229"));
testObjectInputStream();
}
运行结果:
我们发现,static修饰的username序列化之前是xuy,我们在反序列化之前我们对username的值进行了重新赋值,然后反序列化得到的值却为xxxx,这是因为静态变量username是JVM中对应的static变量,而不是序列化后得到的值。
三. transient修饰的变量是否真的不能被序列化?
我们知道,序列化有两种方式,一种是实现Serializable接口,另一种是实现Externalizable接口,两者的区别是:如果实现的是Serializable接口,则会自动的进行序列化。如果实现的是Externalizable接口,我们需要手动的进行序列化。
public class TransientDemo implements Externalizable {
private transient String str = "today is 2018-02-05, and this is about keyword transient";
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(str);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
in.readObject();
}
public static void main(String[] args) {
testObjectOutputStream();
testObjectInputStream();
}
public static void testObjectOutputStream() {
try(ObjectOutputStream ous =
new ObjectOutputStream(new FileOutputStream("xy.txt"))) {
ous.writeObject(new TransientDemo());
ous.flush();
} catch(IOException e) {
e.printStackTrace();
}
}
public static void testObjectInputStream() {
try(ObjectInputStream oin =
new ObjectInputStream(new FileInputStream("xy.txt"))) {
TransientDemo readObject = (TransientDemo) oin.readObject();
System.out.println(readObject.str);
} catch(IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
其中writeExternal()方法调用如下: