【问题标题】:Java ClassNotFoundException when reading object from a stream从流中读取对象时出现 Java ClassNotFoundException
【发布时间】:2012-05-07 09:14:13
【问题描述】:

我在从 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] 错误:无法正确读取对象

【问题讨论】:

  • 发布您的代码。如果你不这样做,那么答案就是“你的猜测和我的一样好”。
  • 请发布您的代码,以及您收到的异常跟踪。

标签: java serialization objectinputstream


【解决方案1】:

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

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

来自ObjectOutputStreamjavadoc:

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

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

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

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

【讨论】:

  • 在发送端,我已经在阅读 .java 并对其进行编译。你认为我可以通过发送 .java 并在接收端编译它来破解一个解决方案吗?
  • 或者,我可以覆盖 writeReplace() 并返回超类吗?
  • @rynojvr:接收端需要能够反序列化它。因此,即使您使用writeReplace() 更改写入流的内容,另一端的对象也需要能够从流中读取字段。换句话说,您在客户端的超类必须有一个自定义的readObject() 方法,该方法知道如何区分字段。
  • @rynojvr:你为什么会有这种“非典型”的安排?
  • 我正在为一个学校项目制作分布式处理网格。客户端应该能够创建他们自己希望网格在其上工作的 WorkUnit。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 它们现在在同一台机器上,但这仅用于开发目的。目标是让某人编写自己的 WorkUnit,然后将其发送出去进行工作。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2018-05-20
      • 2012-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2013-11-08
      相关资源
      最近更新 更多