我已经实例化了一个implements Serializable
的类,我试图像这样传输该对象:
try{
Socket socket = new Socket("localhost", 8000);
ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream());
toServer.writeObject(myObject);
} catch (IOException ex) {
System.err.println(ex);
}
到目前为止一切都好吗?然后我试图像这样读取该对象的字段:
//This is an inner class
class HandleClient implements Runnable{
private ObjectInputStream fromClient;
private Socket socket; // This socket was established earlier
try {
fromClient = new ObjectInputStream(socket.getInputStream());
GetField inputObjectFields = fromClient.readFields();
double myFristVariable = inputObjectFields.get("myFirstVariable", 0);
int mySecondVariable = inputObjectFields.get("mySecondVariable", 0);
//do stuff
} catch (IOException ex) {
System.err.println(ex);
} catch (ClassNotFoundException ex) {
System.err.println(ex);
} finally {
try {
fromClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
但我总是得到错误:
java.io.NotActiveException: not in call to readObject
这是我第一次流式传输对象而不是原始数据类型,我做错了什么?
奖金
当我确实正常工作时,是否整个CLASS与序列化对象一起传递(即我是否可以访问对象类的方法)?我的阅读建议整个类与对象一起传递,但到目前为止我还无法使用对象方法。我究竟如何调用对象的方法?
除了上面的代码,我还尝试了readObject
方法,但我可能也错了,因为我无法使用它。请赐教。
答案 0 :(得分:2)
回答你的第一个问题:
您需要使用ObjectInputStream.readObject
进行反序列化。您无法从流*中读取单个字段。
fromClient = new ObjectInputStream(socket.getInputStream());
Object myObject = fromClient.readObject();
写作时不要忘记刷新输出流!
第二个问题有点复杂。序列化机制的作用是将类标识符写入流,然后是序列化对象数据。当它反序列化时,它将读取类标识符并尝试加载该类(如果它尚未加载)。然后,它将使用no-arg构造函数实例化对象,并调用私有readObject(ObjectInputStream)
方法。是的,没错,它从课外调用私有方法。 Java序列化很特别。
如果找不到类(即如果它不在类路径上),则会抛出异常;否则,如果没有发现其他错误,您将获得正确类型的完全反序列化对象。
例如,假设您有以下类:
class Server {
public static void main(String[] args) {
// Set up an OutputStream sink, e.g. writing to a socket (not shown)
...
ObjectOutputStream out = new ObjectOutputStream(sink);
out.writeObject(new Data("data goes here"));
out.flush();
out.close();
}
}
class Client {
public static void main(String[] args) {
// Set up an InputStream source (not shown)
...
ObjectInputStream in = new ObjectInputStream(source);
Data d = (Data)in.readObject();
System.out.println(d.getData());
}
}
class Data implements java.io.Serializable {
private String data;
public Data(String d) {
data = d;
}
public String getData() {
return data;
}
}
现在假设您将这些类放入三个jar(每个jar一个类):server.jar,client.jar和data.jar。如果您运行以下命令,那么它应该全部工作:
java -cp server.jar:data.jar Server
java -cp client.jar:data.jar Client
但如果你这样做:
java -cp server.jar:data.jar Server
java -cp client.jar Client
然后你会得到一个ClassNotFoundException
,因为客户端不知道如何找到Data
类。
长话短说:类本身不会写入流。如果反序列化成功,那么您将有权访问该对象,就好像它是在本地创建的那样,但您必须将readObject
的结果向下转换为预期的类型。
版本控制存在一些复杂性,我现在已经忽略了。如果版本控制可能成为问题,请查看serialVersionUID
以及如何处理可序列化类的更改。
*严格来说并非如此。您可以在可序列化对象的readFields
方法(或readObject
)中调用readResolve
,但不能从反序列化机制外部调用它。那有意义吗?这有点难以解释。
答案 1 :(得分:0)
查看ObjectInputStream.readFields()
的代码,调用该异常是因为curContext
字段为空。您应该在致电fromClient.readObject()
之前致电readFields()
,因为它会设置curContext
。请注意readObject()
将返回正在序列化的实例,这可能对您有用。