序列化

Java 序列化
序列化作用
注意事项
Java 序列化的缺点
举例说明
项目中曾遇到的一个小问题
参考

序列化定义:将一个对象编码成一个字节流,称作将该对象序列化,反之,将字节流重新构建成对象,则称作反序列化。

序列化作用
序列化将对象编码成字节流,主要用于对象的持久化,远程通信,跨进程访问等地方。
比如开发中常用到的 ORM
框架 Mybatis
,或者 JPA
都是需要将实体类实现序列化接口才能使用,再者如缓存,缓存的对象如果没有实现 Serializable
接口,那么会抛出异常。
注意事项
父类实现了序列化,则子类自动实现了序列化,即子类不需要显式实现 Serializable
接口。
当父类没有实现序列化,而子类需要实现时,子类需要显式实现 Serializable
接口,并且父类中需要有无参的构造函数。
序列化只对对象的属性进行保存,而不会保存其方法。
当类中的实例变量引用了其他对象,那么在对该类进行序列化时,引用的对象也会被序列化。

Java 序列化的缺点
序列化会让类变得不灵活。
实现序列化之后,会有一个序列化 ID ,我们可以使用默认的 ID ,也可以重写这 ID,如果没有显式指定该序列 ID ,系统会经过一系列复杂的计算算出该 ID,那当我们改变类中的方法时,这个 ID 就会变化,这时候往往就会报 InvalidClassException
异常。

序列化可以重构,存在安全隐患。

无法跨语言,Java 进行序列化,别的语言无法进行反序列化。

序列化后的码流太大。

Java 序列化性能较低。

举例说明
父类实现了序列化,则子类自动实现了序列化,即子类不需要显式实现 Serializable
接口

Parent.java

public class Parent implements Serializable { 
int age;
 public Parent(int age)
 { 
this.age = age; 
}
 public int getAge()
 {
 return age; 
}
 public void setAge(int age)
 { 
this.age = age;
 } 
@Override public String toString()
 { 
return "Parent{" + "age=" + age + '}'; }
}

Children.java

public class Children extends Parent { 
public Children(int age) 
{ 
super(age);
 } 
public void say() 
{ 
System.out.println("Hello World " + age);
 } 
@Override public String toString() 
{
 return "Children{" + "} " + super.toString(); }
}

Test.java

public class Test {
 public static void main(String[] args) throws IOException, ClassNotFoundException { 
// 持久化到文件中 Children children = new Children(12);
FileOutputStream outputStream = new FileOutputStream("test.txt"); ObjectOutputStream objectOutputStream = new
ObjectOutputStream(outputStream); objectOutputStream.writeObject(children); 
outputStream.close();
objectOutputStream.close();
// 从文件中读取 FileInputStream inputStream = new FileInputStream("test.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); 
Children o = (Children) objectInputStream.readObject(); 
o.say();
inputStream.close();
objectInputStream.close();
 System.out.println(o);
// new File("test.txt").delete(); }
}

控制台打印出

children

在这个例子中,父类 Parent实现了 Serializable接口,子类序列化时并不需要显式实现 Serializable。当父类没有实现序列化,而子类需要实现时,子类需要显式实现 Serializable接口,并且父类中需要有无参的构造函数。

如果将 Parent改写,不实现序列化,让子类自己来实现会怎样呢?

Parent.java

public class Parent { int age; public Parent(int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Parent{" + "age=" + age + '}'; }}

Children.java

public class Children extends Parent implements Serializable{ public Children(int age) { super(age); } public void say() { System.out.println("Hello World " + age); } @Override public String toString() { return "Children{" + "} " + super.toString(); }}

然后运行 Test.java

error
控制台会打印出没有合适的构造方法。
序列化会让类变得不灵活。

继续改写上述代码(注意:我们上述代码没有重写 serialVersionUID),我们先将该 Children保存到文件中,然后再对 Children进行修改,修改之后,再从文件中把刚才保存的字节码反序列化,看看会出现什么问题。步骤:
运行 Test.java

改写 Children.java,新增字段 name,并改写 say()方法注释掉 Test.java
中的序列化方法,执行其中的反序列化

改写后的 Children.java

public class Children extends Parent {
 private String name; public String getName()
 { 
return name; 
} 
public void setName(String name) {
 this.name = name;
 } 
public Children(int age) { 
super(age);
 }
 public void say() { 
System.out.println("Hello World " + age + ",name: " + name); 
} 
@Override public String toString() {
 return "Children{" + "name='" + name + '\'' + "} " + super.toString(); }
}

控制台打印出:

serial_version_error

为了解决这个问题,我们需要在 Children.java中重写序列化 ID在 Children.java
加入 private static final long serialVersionUID = -1;
即可。
序列化只对对象的属性进行保存,而不会保存其方法。****序列化可以重构,存在安全隐患。

然后重新运行按照上诉步骤重新执行一遍,会发现不会报异常了,并且会发现当我们在运行时期改变 Children
中的 say()方法时,打印出的 say() 方法变了,而 Children中的属性 age
不会改变,且会发现 name默认为 null,这里在运行时我们重构了 Children
类,改变了一些属性及方法,这也就存在了安全隐患。当类中的实例变量引用了其他对象,那么在对该类进行序列化时,引用的对象也会被序列化。如果该引用的对象没有实例化,则不需要序列化。

创建一个 XiaoMing类, 改写 Children ,让 Children包含 XiaoMing的引用,并且在 Children的构造函数中初始化 XiaoMing,然后运行 Test.java。
控制台打印出:

xiaoming_error
表示 XiaoMing
没有实现序列化接口,这说明在序列化对象的时候,对象的引用对象也会被序列化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容