ArrayList中字段serialVersionUID和序列化的学习,
ArrayList中字段serialVersionUID和序列化的学习,
1、功能:serialVersionUID是用来验证版本一致性的字段。我们将一个类的二进制字节序列转为java对象,也就是反序列化时,JVM会把传进来的二进制字节流中的serialVersionUID和本地相应的实体或对象的serialVersionUID进行比较,如果相同,则认为两个类是一致的,可以进行反序列化,否则就会出现版本不一致的反序列化异常。
2、如何定义serialVersionUID:
(1)显示定义:为实现了Serializable的类添加private static final long 类型的字段serialVersionUID,格式如下:
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
}
(2)非显示定义:code中只写接口实现的语法定义,不写上面code中字段serialVersionUID的定义。此时java序列化机制会根据编译生的class文件中的方法和属性为该类自动生成一个serialVersionUID。只要该类的属性和方法不改变,则serialVersionUID不会改变。
3、将serialVersionUID指定为private final static的好处:
因为非显示定义的serialVersionUID对类的方法和属性敏感,只要类中的属性or方法发生改变,则再次编译的class文件对应的serialVersionUID会与之前生成的不一致。如果之前生成的java实例已经被导入到磁盘进行了存储,那么被反序列化时,会出现InvalidCastException异常。
但是,显示定义的serialVersionUID一直不会改变,则不会出现上述异常。
4、序列化时,被声明为transient的字段不能被序列化,这样设置的原因?
首先,序列化的目的是为了传输数据,不管是从内存传到外存,还是从客户端经过网络传到服务器,目的都是为了保存信息。那么被保存的信息中有些信息是敏感的,比如银行卡密码等敏感信息,为了防止在传输过程中发生泄漏,我们就不对敏感信息进行传输,所以通过把这样的字段设置为transient,则不会再被序列化,自然也就不会被传输了。
5、被transient修饰的变量一定不能被序列化吗?
(1)answer:NO
(2)常识:java中序列化有两种方式,一种是实现Serializable接口,另一种是实现Externalizable接口,当然Externalizable继承自Serializable接口。并且由于Serializable序列化的方便性,不用自己手动去写哪些字段需要被序列化,而使用时候更多。
(3)测试:
import java.io.*;
class TestSeriable implements Externalizable {
public transient String name;
public String pwd;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//序列化对象
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(pwd);
out.writeInt(age);
}
//反序列化对象
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name=(String)in.readObject();
pwd=(String)in.readObject();
age=in.readInt();
}
//被序列化的类:必有public类型的无参构造器。因反序列化时,先调用此方法实例化一个类,再调用readExternal方法读取属性值。
public TestSeriable(){
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable ts=new TestSeriable();
ts.setName("cxh");
ts.setPwd("123456");
ts.setAge(3);
//序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test"));
out.writeObject(ts);
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("test"));
ts = (TestSeriable)in.readObject();
//输出:
System.out.println("name:"+ts.name);
System.out.println("pwd:"+ts.pwd);
System.out.println("age:"+ts.age);
//关闭连接
out.close();
in.close();
}
}
输出结果:name:cxh
pwd:123456
age:3
Process finished with exit code 0
6、验证:
(1)实现Serializable接口的类自动生成serialVersionUID ,只要类的属性和方法不改变,则导出字节码就可以被反序列化
&& 被transient修饰的字段不能被序列化。
import java.io.*;
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
private String name;
private int age;
private transient String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable test=new TestSeriable();
test.setAge(27);
test.setName("cxh");
test.setPwd("123456");
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file.txt"));
oos.writeObject(test);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file.txt"));
TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
System.out.println("my name:"+ts.getName());
System.out.println("my age:"+ts.getAge());
System.out.println("my pwd:"+ts.getPwd());
}
}
输出结果:
my name:cxh
my age:27
my pwd:null
Process finished with exit code 0
(2)导出类的属性和方法发生改变,则原来导出的字节码不能被反序列化。
改变:为类TestSeriable添加字段school。
import java.io.*;
class TestSeriable implements Serializable {
private String name;
private int age;
private transient String pwd;
private String school;//新增字段
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable test=new TestSeriable();
test.setAge(27);
test.setName("cxh");
test.setPwd("123456");
// ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file.txt"));
// oos.writeObject(test);
// oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file.txt"));
TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
System.out.println("my name:"+ts.getName());
System.out.println("my age:"+ts.getAge());
System.out.println("my pwd:"+ts.getPwd());
}
}
报错信息:
Exception in thread "main" java.io.InvalidClassException: TestSeriable; local class incompatible: stream classdesc serialVersionUID = 4006342980489649764, local class serialVersionUID = -3721998844011576358
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at Main.main(Main.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Process finished with exit code 1
(3)如果类从一开始被导出前就显示定义了serialVersionUID,则在类的属性或者方法发生更改后,仍然能进行反序列化。
导出前:
import java.io.*;
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static long getSerialVersionUIDs() {
return serialVersionUIDs;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable test=new TestSeriable();
test.setAge(27);
test.setName("cxh");
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file1.txt"));
oos.writeObject(test);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file1.txt"));
TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
System.out.println("my name:"+ts.getName());
System.out.println("my age:"+ts.getAge());
}
}
输出结果:
my name:cxh
my age:27
Process finished with exit code 0
导出后:
import java.io.*;
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
private String name;
private int age;
private String address;//新增字段
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//新增方法
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable test=new TestSeriable();
test.setAge(27);
test.setName("cxh");
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file.txt"));
oos.writeObject(test);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file.txt"));
TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
System.out.println("my name:"+ts.getName());
System.out.println("my age:"+ts.getAge());
}
}
输出结果:
my name:cxh
my age:27
Process finished with exit code 0
(4)一个变量为static修饰后,不管是否被transient修饰,均不能被序列化。
序列化:
import java.io.*;
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
private String name;
private int age;
private static String address;//更改类型为static字段
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//新增方法
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
TestSeriable test=new TestSeriable();
test.setAge(27);
test.setName("cxh");
test.setAddress("海淀");
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file.txt"));
oos.writeObject(test);
oos.close();
// ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file.txt"));
// TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
// System.out.println("my name:"+ts.getName());
// System.out.println("my age:"+ts.getAge());
// System.out.println("my address:"+ts.getAddress());
}
}
查看序列化结果:
import java.io.*;
class TestSeriable implements Serializable {
private static final long serialVersionUID=1L;
private String name;
private int age;
private static String address;//更改类型为static字段
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//新增方法
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Main {
public static void main(String[] args) throws Exception{
//Scanner scanner=new Scanner(System.in);//在线笔试
// TestSeriable test=new TestSeriable();
// test.setAge(27);
// test.setName("cxh");
// test.setAddress("海淀");
//
// ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("file.txt"));
// oos.writeObject(test);
// oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("file.txt"));
TestSeriable ts=(TestSeriable) ois.readObject();//readObject返回final类型的Object对象,需要强制转化
System.out.println("my name:"+ts.getName());
System.out.println("my age:"+ts.getAge());
System.out.println("my address:"+ts.getAddress());
}
}
输出结果:
my name:cxh
my age:27
my address:null
Process finished with exit code 0
相关文章
- 暂无相关文章
用户点评