爪哇 2博客
 爪哇 2博客

用Java可外部化

这是Java序列化教程的第3部分

爪哇 序列化教程:

在了解Externalizable接口之前,您需要对序列化有所了解。 爪哇 序列化.
爪哇 提供了一种称为序列化的机制,以包含对象的字节序或有序序列的形式持久化Java对象’的数据以及有关对象的信息’的类型和存储在对象中的数据类型。

可外部化:

顾名思义,这是对序列化进行外部化。如果要自定义序列化机制,则可以使用它。它使用自定义的书面机制来执行对象的编组和解组.Externalizable接口扩展了Serializable接口。如果实现此接口,则需要重写以下方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
 
    @覆写
    上市 虚空 readExternal(目的Input arg0) 抛出 IOException,
 
            ClassNotFoundException {
 
    }
 
    @覆写
    上市 虚空 writeExternal(目的Output arg0) 抛出 IOException {
 
    }
 

现在让我们看看序列化是如何发生的:

在发送方:
JVM检查类是否实现了可外部化。如果是,则使用writeExternal()方法对对象进行序列化。如果不实现可外部化但实现serializable,则使用ObjectOutputStream对对象进行序列化。

在接收方:
重建对象并使其可外部化时,不使用args构造函数创建实例,并调用readExternal。如果该对象不可外部化但可序列化,则使用ObjectInputStream重建对象。

让我们以与我们在 爪哇 序列化.
Create 雇员.java 在 src-> 组织 .arpit.java2blog

雇员.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .可外部化;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的Input;
进口 爪哇 . io .目的Output;
 
上市 雇员 实施 可外部化{
 
整型 员工ID;
员工姓名;
部门;
国籍;
 
上市 雇员()
{
 
}
上市 整型 getEmployeeId() {
   返回 员工ID;
}
上市 虚空 setEmployeeId( 整型 员工ID) {
   这个 .员工ID = 员工ID;
}
上市 getEmployeeName() {
   返回 员工姓名;
}
上市 虚空 setEmployeeName( 员工姓名) {
   这个 .员工姓名 = 员工姓名;
}
上市 getDepartment() {
   返回 部门;
}
上市 虚空 setDepartment( 部门) {
   这个 .部门 = 部门;
}
 
上市 getNationality() {
   返回 国籍;
}
上市 虚空 国籍( 国籍) {
   这个 .国籍 = 国籍;
}
@覆写
上市 虚空 readExternal(目的Input ) 抛出 IOException,
ClassNotFoundException {
  员工ID=.readInt ();
  员工姓名=() .readObject();
 
}
@覆写
上市 虚空 writeExternal(目的Output ) 抛出 IOException {
 
  .writeInt(员工ID);
  .writeObject(员工姓名);
}
}
 

如果要实现可外部化,则必须没有args构造函数。

在org.arpit.java2blog中创建ExternalizableMain.java
可外部化Main.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .FileInputStream;
进口 爪哇 . io .FileOutputStream;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的InputStream;
进口 爪哇 . io .目的OutputStream;
 
上市 可外部化Main {
/ **
  * @作者Arpit Mandliya
  */
上市 静态的 虚空 主要 ([] args ) {
 
  雇员 emp = 雇员();
   emp .setEmployeeId(101);
   emp .setEmployeeName( “阿尔伯特” );
   emp .setDepartment( “ CS ” );
 
  //连载
   尝试
  {
   FileOutputStream fileOut = FileOutputStream(“ emp loyee.ser”);
   目的OutputStream 外流 = 目的OutputStream(fileOut);
   外流.writeObject( emp );
   外流.();
   fileOut.();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
  }
 
  //反序列化
   emp = 空值 ;
   尝试
  {
   FileInputStream fileIn = FileInputStream(“ emp loyee.ser”);
   目的InputStream = 目的InputStream( fileIn );
   emp = (雇员) .readObject();
   .();
   fileIn .();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
   返回 ;
  } 抓住 (ClassNotFoundException c)
  {
   系统 .. 打印 (“未找到员工类别”);
   c.printStackTrace();
   返回 ;
  }
   系统 .. 打印 (“反序列化的员工...”);
   系统 .. 打印 (“ Emp ID:” + emp .getEmployeeId());
   系统 .. 打印 (“名称: ” + emp .getEmployeeName());
 
}
}
 

运行 :

当您运行ExternalizableMain.java时,您将获得以下输出

1
2
3
4
5
 
反序列化 雇员...
Emp ID : 101
名称 : Arpit
 

如果您已经具有可序列化的功能,那么为什么根本不需要外部化!:

  • 当您使用serializable可序列化任何对象时,除字段外,所有属于对象映射且可以使用实例变量访问的对象也将被序列化。例如:
    • 如果您拥有Employee类,并且其超类是person,那么它将序列化所有超类对象(例如person),直到达到“Object” 类 .
    • 同样,如果Employee具有地址类的实例变量,则它将也序列化整个地址对象图。

当您要序列化的所有文件都是employeeId和employeeName时,您真的要这么多开销吗?

  • 当您使用序列化速度很慢时,JVM使用反射。
  • 进行序列化时,有关类描述的信息(包括其超类的描述和与该类关联的实例变量)也会存储在流中。同样,这也是性能问题

继承中的继承:

现在我们将了解继承如何影响外部化,因此可能会有很多情况说明超类是否可外部化。
我们将创建Person.java,它将是Employee的超类。

情况1:如果超类未实现Externalizable:

如果超类未实现可外部化,则需要序列化超类‘实现Externalizable的子类中的s字段。

人.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
组织 . Arpit . 爪哇 2blog;
上市 {
 
名称 =“默认”;
国籍;
 
上市 ()
{
   系统 .. 打印 (“人:构造函数”);
}
 
上市 ( 名称 , 国籍) {
  ();
   这个 . 名称 = 名称 ;
   这个 .国籍 = 国籍;
}
 
上市 getName () {
   返回 名称 ;
}
 
上市 虚空 setName( 名称 ) {
   这个 . 名称 = 名称 ;
}
 
上市 getNationality() {
   返回 国籍;
}
 
上市 虚空 国籍( 国籍) {
   这个 .国籍 = 国籍;
}
 
}
 

在org.arpit.java2blog中创建Employee.java
雇员.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .可外部化;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的Input;
进口 爪哇 . io .目的Output;
;
 
上市 雇员 延伸 实施 可外部化{
 
整型 员工ID;
部门;
 
上市 雇员()
{
 
}
上市 雇员( 整型 员工ID, 名称 , 部门, 国籍)
{
  ( 名称 ,国籍);
   这个 .员工ID=员工ID;
   这个 .部门=部门;
   系统 .. 打印 (“员工:构造函数”);
}
 
上市 整型 getEmployeeId() {
   返回 员工ID;
}
上市 虚空 setEmployeeId( 整型 员工ID) {
   这个 .员工ID = 员工ID;
}
 
上市 getDepartment() {
   返回 部门;
}
上市 虚空 setDepartment( 部门) {
   这个 .部门 = 部门;
}
 
@覆写
上市 虚空 writeExternal(目的Output ) 抛出 IOException {
 
/ *由于超类无法实现可外部化,因此您需要在此类本身中序列化超类字段* /
//超类字段
.writeObject( 名称 );
.writeObject(国籍);
 
//自己的字段
.writeInt(员工ID);
.writeObject(部门);
}
 
@覆写
上市 虚空 readExternal(目的Input ) 抛出 IOException,
  ClassNotFoundException {
/ *由于超类无法实现可外部化,因此您需要在此类本身中反序列化超类字段* /
//超类字段
名称 =() .readObject();
国籍=() .readObject();
 
//自己的字段
员工ID=.readInt ();
部门=() .readObject();
 
}
}
 

在org.arpit.java2blog中创建ExternalizableMain.java

可外部化Main.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .FileInputStream;
进口 爪哇 . io .FileOutputStream;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的InputStream;
进口 爪哇 . io .目的OutputStream;
 
上市 可外部化Main {
 
  / **
  * @作者Arpit Mandliya
  * /
  上市 静态的 虚空 主要 ([] args ) {
 
  //连载
  雇员 emp = 雇员(101, “阿尔伯特” , “ CS ” ,“印度人”);
  系统 .. 打印 (“序列化之前”);
  系统 .. 打印 (“ Emp ID:” + emp .getEmployeeId());
  系统 .. 打印 (“名称: ” + emp . getName ());
  系统 .. 打印 (“部门: ” + emp .getDepartment());
  系统 .. 打印 (“国籍:” + emp .getNationality());
  系统 .. 打印 (“ ************”);
  系统 .. 打印 (“序列化”);
  尝试
  {
   FileOutputStream fileOut = FileOutputStream(“ emp loyee.ser”);
   目的OutputStream 外流 = 目的OutputStream(fileOut);
   外流.writeObject( emp );
   外流.();
   fileOut.();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
  }
 
  //反序列化
  系统 .. 打印 (“ ************”);
  系统 .. 打印 (“反序列化”);
  emp = 空值 ;
  尝试
  {
   FileInputStream fileIn = FileInputStream(“ emp loyee.ser”);
   目的InputStream = 目的InputStream( fileIn );
   emp = (雇员) .readObject();
   .();
   fileIn .();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
   返回 ;
  } 抓住 (ClassNotFoundException c)
  {
   系统 .. 打印 (“未找到员工类别”);
   c.printStackTrace();
   返回 ;
  }
  系统 .. 打印 (“序列化之后”);
  系统 .. 打印 (“ Emp ID:” + emp .getEmployeeId());
  系统 .. 打印 (“名称: ” + emp . getName ());
  系统 .. 打印 (“部门: ” + emp .getDepartment());
  系统 .. 打印 (“国籍:” + emp .getNationality());
 }
}
 

运行 :

当运行ExternalizableMain.java时,您将获得以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
雇员:建设者
之前 序列化
Emp ID : 101
名称 : Arpit
部门: CS
国籍: 印度人
************
序列化
************
反序列化
:建设者
序列化
Emp ID : 101
名称 : Arpit
部门: CS
国籍: 印度人
 

情况2:如果超类实现了Externalizable:

如果超类实现了externalizable,那么它还将具有readExternal()和writeExternal()方法,因此它将在这些方法中序列化自己的字段

人.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
组织 . Arpit . 爪哇 2blog;
 
进口 爪哇 . io .可外部化;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的Input;
进口 爪哇 . io .目的Output;
 
上市 实施 可外部化{
 
名称 =“默认”;
国籍;
 
上市 ()
{
   系统 .. 打印 (“人:构造函数”);
}
 
上市 ( 名称 , 国籍) {
  ();
   这个 . 名称 = 名称 ;
   这个 .国籍 = 国籍;
}
 
上市 getName () {
   返回 名称 ;
}
 
上市 虚空 setName( 名称 ) {
   这个 . 名称 = 名称 ;
}
 
上市 getNationality() {
   返回 国籍;
}
 
上市 虚空 国籍( 国籍) {
   这个 .国籍 = 国籍;
}
 
@覆写
上市 虚空 writeExternal(目的Output ) 抛出 IOException {
 
  .writeObject( 名称 );
  .writeObject(国籍);
}
 
@覆写
上市 虚空 readExternal(目的Input ) 抛出 IOException,
ClassNotFoundException {
   名称 =() .readObject();
  国籍=() .readObject();
 
}
 
}
 

在org.arpit.java2blog中创建Employee.java
雇员.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .可外部化;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的Input;
进口 爪哇 . io .目的Output;
;
 
上市 雇员 延伸 实施 可外部化{
 
整型 员工ID;
部门;
 
上市 雇员()
{
 
}
上市 雇员( 整型 员工ID, 名称 , 部门, 国籍)
{
  ( 名称 ,国籍);
   这个 .员工ID=员工ID;
   这个 .部门=部门;
   系统 .. 打印 (“员工:构造函数”);
}
 
上市 整型 getEmployeeId() {
   返回 员工ID;
}
上市 虚空 setEmployeeId( 整型 员工ID) {
   这个 .员工ID = 员工ID;
}
 
上市 getDepartment() {
   返回 部门;
}
上市 虚空 setDepartment( 部门) {
   这个 .部门 = 部门;
}
 
@覆写
上市 虚空 writeExternal(目的Output ) 抛出 IOException {
 
  .writeExternal();
  .writeInt(员工ID);
  .writeObject(部门);
}
 
@覆写
上市 虚空 readExternal(目的Input ) 抛出 IOException,
ClassNotFoundException {
 
  .readExternal();
  员工ID=.readInt ();
  部门=() .readObject();
 
}
}
 

在org.arpit.java2blog中创建ExternalizableMain.java

可外部化Main.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 
组织 . Arpit . 爪哇 2blog;
进口 爪哇 . io .FileInputStream;
进口 爪哇 . io .FileOutputStream;
进口 爪哇 . io .IOException;
进口 爪哇 . io .目的InputStream;
进口 爪哇 . io .目的OutputStream;
 
上市 可外部化Main {
 
  / **
  * @作者Arpit Mandliya
  * /
  上市 静态的 虚空 主要 ([] args ) {
 
  //连载
  雇员 emp = 雇员(101, “阿尔伯特” , “ CS ” ,“印度人”);
  系统 .. 打印 (“序列化之前”);
  系统 .. 打印 (“ Emp ID:” + emp .getEmployeeId());
  系统 .. 打印 (“名称: ” + emp . getName ());
  系统 .. 打印 (“部门: ” + emp .getDepartment());
  系统 .. 打印 (“国籍:” + emp .getNationality());
  系统 .. 打印 (“ ************”);
  系统 .. 打印 (“序列化”);
  尝试
  {
   FileOutputStream fileOut = FileOutputStream(“ emp loyee.ser”);
   目的OutputStream 外流 = 目的OutputStream(fileOut);
   外流.writeObject( emp );
   外流.();
   fileOut.();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
  }
 
  //反序列化
  系统 .. 打印 (“ ************”);
  系统 .. 打印 (“反序列化”);
  emp = 空值 ;
  尝试
  {
   FileInputStream fileIn = FileInputStream(“ emp loyee.ser”);
   目的InputStream = 目的InputStream( fileIn );
   emp = (雇员) .readObject();
   .();
   fileIn .();
  } 抓住 (IOException i)
  {
   i.printStackTrace();
   返回 ;
  } 抓住 (ClassNotFoundException c)
  {
   系统 .. 打印 (“未找到员工类别”);
   c.printStackTrace();
   返回 ;
  }
  系统 .. 打印 (“序列化之后”);
  系统 .. 打印 (“ Emp ID:” + emp .getEmployeeId());
  系统 .. 打印 (“名称: ” + emp . getName ());
  系统 .. 打印 (“部门: ” + emp .getDepartment());
  系统 .. 打印 (“国籍:” + emp .getNationality());
 }
}
 

运行 :

当运行ExternalizableMain.java时,您将获得以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
雇员:建设者
之前 序列化
Emp ID : 101
名称 : Arpit
部门: CS
国籍: 印度人
************
序列化
************
反序列化
:建设者
序列化
Emp ID : 101
名称 : Arpit
部门: CS
国籍: 印度人
 

在此示例中,由于Person类在其自己的writeExternal和readExternal方法中存储和还原其字段,因此您无需在子类中保存/恢复超类字段,但是如果您仔细观察Employee类的writeExternal和readExternal方法,您将发现您仍然需要首先调用super.xxxx()方法,该方法确认可外部化对象还必须与其父类型协调才能保存和恢复其状态的语句。

可外部化的缺点:

  • 如果对类定义进行了任何更改,则需要相应地维护writeExternal()和readExternal。
  • 正如我们在示例中看到的,子类对象必须与其父类协调才能保存和存储其状态(通过从子类中调用super.xxxx()方法)

分享这个

作者

关注作者

相关文章

  • 序列化面试问题
    2月14日

    爪哇 序列化面试问答

    序列化是Java中最重要的概念之一。如果您要面对核心Java面试,那么可能会从序列化中询问您一些问题。 爪哇 序列化教程:java中的序列化Java序列化访谈问题和答案Java序列化中的serialversionuid在Java中可外部化Java中的Transient关键字Serializable和Externalizable […]

  • 2月14日

    爪哇 中可序列化和可外部化之间的区别

    在本教程中,我们将看到Java中可序列化和可外部化接口之间的区别。 爪哇 序列化教程:Java的序列化Java序列化访谈问答Java的序列化Java的序列化Java的可外部化Java的Transient关键字Java的可序列化和可外部化之间的区别在理解差异之前,让我简要介绍一下Serializable […]

  • 19 May

    爪哇 瞬时关键字与示例

    瞬态变量是其值在序列化过程中未序列化的变量。反序列化时,将获得这些变量的默认值。假设您有乡村课程而您没有’不想序列化总体属性,因为它会随着时间而变化,因此您可以将总体属性声明为瞬态,它会’t […]

  • 3月11日

    爪哇 序列化中的serialVersionUID

    这是Java序列化教程的第二部分Java序列化教程:Java序列化Java序列化访谈问答Java序列化中的serialversionuid在Java中可外部化Java中的Transient关键字Java中Serializable和Externalizable之间的区别serialVersionUID用于确保相同的类(在反序列化过程中加载序列化期间使用的序列。serialVersionUID为[…]

  • 3月9日

    爪哇 序列化

    这是Java序列化教程的第1部分。 爪哇 序列化教程:Java的序列化Java序列化访谈问答Java的serialversionuid 爪哇 的外部序列化Java的Transient关键字Java的Serializable和Externalizable之间的区别Java提供了一种称为序列化的机制,以序列或字节序列形式持久化Java对象[…]

Comments

  1. 嗨Arpit,

    我赞赏它的良好主动性。我在想一些问题。

    在继承的情况下,如果我不这样做'选择序列化父类和Stil的字段我尝试在main方法中反序列化thode字段,我会得到任何异常吗?

    在情况2中,如果我没有在readExternal和writeExternal方法中调用super.xxx()怎么办。默认情况下,JVM是否会调用父级重写的方法?

  2. 嗨,阿维纳什,
    谢谢
    如果情况为1-否,则胜诉'给您例外,它将为您提供Parent类字段的默认值。
    如果情况2- JVM获胜't call parent's默认情况下覆盖的方法。您需要明确地调用它

发表评论 取消回复

您的电子邮件地址不会被公开。 必需的地方已做标记 *

订阅我们的新闻

获取质量教程到您的收件箱。现在订阅。


成为朋友

©2020 爪哇 2博客