通过Java套接字传递对象 |
发布: 2010-03-20
返回
|
使用JavaTM远程方法调用(RMI),可以很方便地开发分布式的基于对象的应用程序。RMI的简单性,是由网络通信的费用作为代价的。底层的套接字可以用来开发客户/服务器系统,但是由于大多数Java I/O类和对象不太容易匹配,如何通过套接字传递完成的对象呢?对象序列化是一个允许您以比特流方式读/写完成对象的机制。 将底层的套接字和对象序列化结合在一起,您将得到一个强大的、高效的、可替代RMI的机制,通过套接字来传递对象还能克服使用RMI的高费用的问题。 对象序列化概述 将对象读出或者写入流的主要类有两个: ObjectOutputStream与ObjectInputStream 。ObjectOutputStream 提供用来将对象写入输出流的writeObject方法, ObjectInputStream提供从输入流中读出对象的readObject方法。注意使用这些方法的对象必须被序列化,这非常重要。也就是说,这些类必须实现Serializable接口。 序列化已经存在的类 注意: Date类是可序列化的。换句话说,它实现 Serializable接口。 例程 1: SaveDate.java Java代码 import java.io.*; import java.util.Date; public class SaveDate { public static void main(String argv[]) throws Exception { FileOutputStream fos = new FileOutputStream("date.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); Date date = new Date(); oos.writeObject(date); oos.flush(); oos.close(); fos.close(); } } 读入对象,然后重新构造它的状态都很容易。例程2中的代码向您展示了如何读一个已经序列化的对象并且打印它的信息。 例程 2: ReadDate.java Java代码 import java.io.*; import java.util.Date; public class ReadDate { public static void main(String argv[]) throws Exception { FileInputStream fis = new FileInputStream("date.out"); ObjectInputStream ois = new ObjectInputStream(fis); Date date = (Date) ois.readObject(); System.out.println("The date is: "+date); ois.close(); fis.close(); } } 在上面的例子中我们使用了Date类的一个实例,这是一个现成的已序列化的Java类。也许您会问这样的问题:是不是所有现成的Java类都是可序列化的?答案是否定的。这不仅因为这样做没必要,而且将某些类序列化是毫无意义的。使用JDK中的serialver工具,可以判断一个类是不是可序列化的。您可以在命令行模式下使用如下命令: Java代码 c:\> serialver java.util.Date java.util.Date: static final long serialVersionUID = 7523967970034938905L; (这个例子测试Date类是不是可序列化。输出结果表示Date类是可序列化的,并且打印出了这个类的版本唯一标识符。) 或者,您也可以使用如下命令启动图形界面下的serialver工具: c:\> serialver -show 这个命令将弹出一个如图1所示的窗口,在这个窗口中写入您想检查的类的名字(包括路径)。图1显示的结果表示 Date类是可序列化的。 再说一次,不是所有的Java类都是可序列化的。举个例子,图2表明Socket类是不可序列化的。 序列化用户自己的类
现在,让我们看看如何序列化用户自己写的类。在这个例子中,我们将建立一个用户类UserInfo,见例程3。为了让它可序列化,UserInfo类实现了Serializable接口。
例程 3: UserInfo.java
import java.io.*; import java.util.*;
public class UserInfo implements Serializable { String name = null;
public UserInfo(String name) { this.name = name; }
public void printInfo() { System.out.println("The name is: "+name); } }
下一步就是建立一个能创建UserInfo类实例的类,然后将对象写入输出流中,如例程4。本例中的输出流是一个名为"name.out"的文件。要注意的是,例程4 中的writeObject方法可以被调用任意多次,将任意多个对象写入输出流。
例程 4: SaveInfo.java
import java.io.*; import java.util.Date;
public class SaveInfo {
public static void main(String argv[]) throws Exception { FileOutputStream fos = new FileOutputStream("name.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); // create two objects UserInfo user1 = new UserInfo("Java Duke"); UserInfo user2 = new UserInfo("Java Blue"); // write the objects to the output stream oos.writeObject(user1); oos.writeObject(user2); oos.flush(); oos.close(); fos.close(); } }
最后,我们写一个将已经保存的对象读入的类,并且调用一个如例程5所示的方法。和writeObject 一样,readObject方法能被调用任意多次,从输入流中读入任意多个对象。
例程 5: ReadInfo.java
import java.io.*; import java.util.Date;
public class ReadInfo {
public static void main(String argv[]) throws Exception { FileInputStream fis = new FileInputStream("name.out"); ObjectInputStream ois = new ObjectInputStream(fis); // read the objects from the input stream (the file name.out) UserInfo user1 = (UserInfo) ois.readObject(); UserInfo user2 = (UserInfo) ois.readObject(); // invoke a method on the constructed object user1.printInfo(); user2.printInfo(); ois.close(); fis.close(); } }
要测试这个例子,请编译如下源文件:UserInfo.java, SaveInfo.java, 和 ReadInfo.java。运行 SaveInfo,然后运行ReadInfo,将看到类似下面的输出结果:
The name is: Java Duke The name is: Java Blue |