在Java中访问序列化对象的字段时出现问题

在Java中访问序列化对象的字段时出现问题,java,serialization,object,stream,Java,Serialization,Object,Stream,我实例化了一个类,该类实现了可序列化,我正试图像这样流式处理该对象: try{ Socket socket = new Socket("localhost", 8000); ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream()); toServer.writeObject(myObject); } catch (IOException ex) { System.e

我实例化了一个类,该类
实现了可序列化
,我正试图像这样流式处理该对象:

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();
        }
    }
}
到目前为止一切都很好,对吗?然后我尝试读取该对象的字段,如下所示:

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:不在readObject调用中

这是我第一次流化对象而不是原始数据类型,我做错了什么

奖金

当我正确运行时,整个类是否随序列化对象一起传递(即,我是否有权访问对象类的方法)?我的阅读表明,整个类都与对象一起传递,但到目前为止,我还无法使用objects方法。我如何准确地调用对象的方法


除了上面的代码之外,我还尝试了
readObject
方法,但我可能也用错了,因为我无法让它工作。请告诉我。

查看
ObjectInputStream.readFields()
的代码,调用该异常是因为
curContext
字段为空。在调用
readFields()
之前,您应该调用
fromClient.readObject()
,因为它将设置
curContext
。请注意,
readObject()
将返回正在序列化的实例,这可能对您更有用。

要回答您的第一个问题:

您需要使用
ObjectInputStream.readObject
进行反序列化。无法从流*中读取单个字段

fromClient = new ObjectInputStream(socket.getInputStream());
Object myObject = fromClient.readObject();
写入时不要忘记刷新输出流

第二个问题有点复杂。序列化机制所做的是将类标识符写入流,后跟序列化的对象数据。当它反序列化时,它将读取类标识符并尝试加载该类(如果尚未加载)。然后,它将使用no-arg构造函数实例化对象,并调用private
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
,因为客户端不知道如何查找
数据

长话短说:类本身并没有写入流。如果反序列化成功,则您将可以访问对象,就像它是本地创建的一样,但您必须将
readObject
的结果向下转换为预期类型

版本控制有一些复杂性,我现在已经忽略了。查看
serialVersionUID
,以及如果版本控制可能成为一个问题,如何处理对可序列化类的更改


*不完全正确。您可以在可序列化对象的
readObject
方法(或
readResolve
)内部调用
readFields
,但不能从反序列化机制外部调用它。这有意义吗?这有点难以解释。

谢谢,你为我澄清了两个要点。我没有意识到“服务器”和“客户端”都需要相关类的本地副本。我也没有意识到我需要强制转换对象类型。我想现在一切都好了。