3

从 ObjectInputStream 读取对象时出现 ClassNotFoundException。正在发送的对象是读取代码引用的“WorkUnit”的子类。接收端似乎在抱怨,因为它不知道具体的实现。当我只在接收端引用对象的超类:“WorkUnit”时,它为什么会关心这个?

从 Stream 读取的代码:

private Object readObject() {
    Object object = null;
    try {
        object = objectIn.readObject();
    } catch (SocketException | EOFException e) {
        // Socket was forcedly closed. Probably means client was
        // disconnected
        System.out.println("[NetworkHandler] SOCKET CLOSED");
        shouldContinue = false;
        if (!isClient)
            server.clientDisconnected(clientID);
    } catch (ClassNotFoundException | IOException e) {
        // If shouldContinue is true, we haven't said that we want to close
        // the connection
        if (shouldContinue) {
            e.printStackTrace();
            System.err
                    .println("[NetworkHandler] Error: Couldn't read object correctly");
        }
    }
    return object;
}

工作单位实施:

import java.util.LinkedList;
import java.util.List;

import Application.WorkUnit;


public class WorkUnitImplementation extends WorkUnit<Integer, Integer> {

private static final int INPUT_LENGTH = 1000;

public WorkUnitImplementation() {
    super();

    setInputLength(INPUT_LENGTH);
}

@Override
public Integer doWork(Integer input) {
    wait(50);
    return (input % 2 == 1) ? input : null;
}

@Override
public List<Integer> inputFactory(int begin, int end) {
    List<Integer> result = new LinkedList<>();
    for (int i = begin; i < end; i++) {
        result.add(i);
    }
    return result;
}

private void wait(int time) {
    try {
        Thread.sleep(time);
    } catch (Exception e) {

    }
}
}

发送工作单元的代码:

    public void uploadWorkUnit(WorkUnit workUnit) {
    try {
        objectOut.writeObject(new UploadWorkUnit(workUnit));
        objectOut.flush();
        System.out.println("[NetworkHandler] Uploaded workUnit");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

异常跟踪:

java.lang.ClassNotFoundException: WorkUnitImplementation
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:622)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at Networking.NetworkHandler.readObject(NetworkHandler.java:188)
at Networking.NetworkHandler.run(NetworkHandler.java:90)
at java.lang.Thread.run(Thread.java:722)

[NetworkHandler] 错误:无法正确读取对象

4

4 回答 4

2

接收端似乎在抱怨,因为它不知道具体的实现。当我只在接收端引用对象的超类:“WorkUnit”时,它为什么会关心这个?

这是因为流由实现类的字段组成。

来自ObjectOutputStreamjavadoc:

对象的默认序列化机制写入对象的类、类签名以及所有非瞬态和非静态字段的值。

反序列化过程读取流以发现应该自动重组的类。它尝试创建该类的新实例,以便随后可以使用流中包含的字段填充它。

如果接收端没有编写的相同类,它将无法工作——你会得到一个ClassNotFoundException.

(也就是说,被序列化的类可以使用writeReplace(),但这可能超出了这个问题的范围)。

于 2012-05-07T09:24:35.843 回答
2

我有时遇到同样的问题,我通过将要通过网络发送的类放在它自己的包中(在发送端和接收端)然后将其导入到发送它的类中来解决它或已收到。请注意,两端的包结构应该相同。

于 2012-12-09T21:19:58.640 回答
0

作为猜测,您在不同的机器上运行发送者和接收者。您是否检查过他们在每个字段上都有相同版本的此类?

于 2012-05-07T09:22:50.337 回答
0

是的,我有同样的问题。我已经通过在同一个包上使用相同的序列化类来解决它。将 ObjectOutputStream 和 ObjectInputStream 函数放在同一个包中,分别执行输出、输入或调用。

于 2016-08-23T16:29:21.867 回答