java关键字之transient
一、作用
被transient修饰的变量不参与序列化和反序列化
transient关键字只能修饰变量,而不能修饰方法和类。注意,局部变量是不能被transient关键字修饰的。
一个静态变量不管是否被transient修饰,均不能被序列化。
二、实践测试
import java.io.Serializable;
public class User implements Serializable{
/**
* 自动生成的序列号
*/
//private static final long serialVersionUID = 3810909334566607723L;
private static final long serialVersionUID = 1L;
private String name;
private transient int age;
public static String sex;
public static transient String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static String getSex() {
return sex;
}
public static void setSex(String sex) {
User.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static String getPassword() {
return password;
}
public static void setPassword(String password) {
User.password = password;
}
public String show() {
return "姓名:"+name+"\t"+"密码:"+password+"\t"+"性别:"+sex+"\t"+"年龄:"+age;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import com.depart.entity.User;
public class TestTransient {
@SuppressWarnings("resource")
public static void main(String[] args) {
User user = new User();
user.setAge(22);
user.setName("chenfuzhe");
User.setPassword("csdn");//设置静态变量的值
User.setSex("man");//设置静态变量的值
System.out.println(user.show());
try {
//序列化
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("tempFile"));
outputStream.writeObject(user);
outputStream.close();
System.out.println("==========我是一条温暖的分隔线==========");
//反序列化
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("tempFile"));
User userOut = (User)inputStream.readObject();
System.out.println(userOut.show());
//姓名:chenfuzhe 密码:csdn 性别:man 年龄:0,其中输出了密码和性别的值,年龄没有值
//输出结果为什么有值呢,难道static能被序列化?不是的,其实是因为在反序列化之前set了值,
//相当于在给静态变量User.sex设置了值,在show()中,我调用就是静态变量的值,所以密码和性别被打印出来了,
//当把反序列化移到另外一个测试类中,也就是不在同一线程中时,静态变量User.sex也就没有值了
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.depart.entity.User;
public class TestTransient2 {
public static void main(String[] args) {
ObjectInputStream inputStream;
User userOut;
try {
//反序列化
inputStream = new ObjectInputStream(new FileInputStream("tempFile"));
userOut = (User)inputStream.readObject();
System.out.println(userOut.show());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三、序列化扩展
1. 用法
序列化时,被序列化的类需要实现一个Serializable 接口,这个接口是空接口,没有任何方法,相当于一个标识,同时,需要生成一个 serialVersionUID ,且必须是静态常量,如:private static final long serialVersionUID = 3810909334566607723L;
注意 :使用static final 修饰,final修饰是为了避免修改,而使用private修饰则使得值难以被获取。
2. 问题
如果我们不生成,序列化时,java会根据class文件自动生成一个serialVersionUID ,同时在反序列化时再根据class文件生成一个serialVersionUID,值是一样的,反序列化成功,通过这种前后对比的方式,可以保证了程序的安全性,可以防止外部文件被修改,从而携带恶意脚本,造成程序错误的问题。 但是如果我们在序列化后修改了java文件的serialVersionUID,class文件也发生了改变,序列化和反序列化前后的class文件不一样,serialVersionUID也不一样,就会抛出InvalidClassException异常
例如:当我们不声明类的serialVersionUID,序列化成功后,修改java文件的serialVersionUID = 3810909334566607723,再去反序列化,就会出现如下异常
java.io.InvalidClassException: com.depart.entity.User; local class incompatible: stream classdesc serialVersionUID = 8733796526853314695, local class serialVersionUID = 3810909334566607723
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)
at com.depart.test.TestTransient2.main(TestTransient2.java:17)
3. serialVersionUID获取
使用serialver 命令生成serialVersionUID
注意:类中没有声明serialVersionUID,他会自动生成一个值,如:private static final long serialVersionUID = 3810909334566607723L; 如果有会返回声明的 serialVersionUID, 如:private static final long serialVersionUID = 1L;
4. static 和 transient在序列化和反序列化的区别
transient 关键字修饰的变量在序列化时,会被一同序列化,但是值会被清空,所以反序列化出来就是默认值了
static 关键字修饰的变量在序列化时,不会被序列化,反序列化后,显示的值只是默认值