为什么在其源文件Java中看不到类

时间:2012-05-18 06:53:35

标签: java classnotfoundexception

无论我做什么,我都无法创建Serwer类的新实例。请帮助,不知何故构造函数是隐形的。我不明白为什么会这样。构造函数是公共的,所有内容都编码在一个文件中。

我得到这个:

java.rmi.StubNotFoundException: Stub class not found: Serwer_Stub; nested exception is: 
java.lang.ClassNotFoundException: Serwer_Stub
at sun.rmi.server.Util.createStub(Unknown Source)
at sun.rmi.server.Util.createProxy(Unknown Source)
at sun.rmi.server.UnicastServerRef.exportObject(Unknown Source)
at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source)
at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source)
at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.exportObject(Unknown Source)
at javax.rmi.PortableRemoteObject.exportObject(Unknown Source)
at javax.rmi.PortableRemoteObject.<init>(Unknown Source)
at Serwer.<init>(Serwer.java:13)
at Serwer.main(Serwer.java:35)
Caused by: java.lang.ClassNotFoundException: Serwer_Stub
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 10 more

CLASS

import java.rmi.RemoteException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.rmi.PortableRemoteObject;

public class Serwer extends PortableRemoteObject implements MyInterface {



public Serwer() throws RemoteException {
    super();
    try{
        Serwer ref =
                new Serwer();
        Context ctx = new InitialContext();
        ctx.rebind("myinterfaceimplementacja", ref);

    }catch(Exception e){e.printStackTrace();}
}

@Override
public String echo(String napis) throws RemoteException {
    return "echo" + napis;
}

@Override
public int dodaj(int wrt1, int wrt2) throws RemoteException {
    return wrt1 + wrt2;
}

public static void main(String[] args){
    try {
        new Serwer();
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
}

1 个答案:

答案 0 :(得分:2)

您的代码中有两个错误。第一个是Serwer构造函数中明显的无限递归,您在这里一次又一次地调用构造函数。这可以通过从构造函数中删除该行来修复,并将ref替换为以下行中的this

public class Serwer extends PortableRemoteObject implements MyInterface {

    public Serwer() throws RemoteException {
        super();
    }

    @Override
    public String echo(String napis) throws RemoteException {
        return "echo" + napis;
    }

    @Override
    public int dodaj(int wrt1, int wrt2) throws RemoteException {
        return wrt1 + wrt2;
    }

    public static void main(String[] args){
        try {
            Serwer ref = new Serwer();
            // Context ctx = new InitialContext();
            // ctx.rebind("myinterfaceimplementacja", ref);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

但是,此错误与您获得的ClassNotFoundException无关。导致异常的原因是您使用PortableRemoteObject作为远程实现的基类。通常在Java RMI中,导出(实例化)远程对象时会自动生成存根类(Serwer_Stub)。但是PortableRemoteObject是这种情况的一个例外。您可以通过以下两种方式解决:

  1. 正如库马尔建议的那样,将javax.rmi.PortableRemoteObject替换为java.rmi.server.UnicastRemoteObject。这样就可以自动创建存根对象,上面的代码将很快运行,我测试了它。

    public class Serwer extends UnicastRemoteObject implements MyInterface {
    
  2. 如果由于某种原因你必须使用PortableRemoteObject,那么你应该使用JDK附带的RMI编译器(rmic)工具手动生成存根类。

    首先,编译Serwer类:

    javac Serwer.java
    

    这将生成Serwer.class文件。然后调用RMIC工具生成存根类:

    rmic Serwer
    

    这将生成Serwer_Stub.class文件。现在您可以运行服务器了:

    java Serwer
    

    我也对此进行了测试,它没有任何例外。

  3. 请注意,您的代码中存在另一个使用Java命名的错误,导致另一个异常(NoInitialContextException),但这也与问题无关,这就是我在上面的代码中对其进行评论的原因。由于我不是javax.naming的专家,因此由其他人来帮助你。

    也许您打算使用RMI注册表而不是错误地使用Naming。 RMI注册表是在Java RMI中绑定和查找远程对象的本机方式。在这种情况下,您应该替换

    Context ctx = new InitialContext();
    ctx.rebind("myinterfaceimplementacja", ref);
    

    带有相应RMI注册码的行:

    Registry reg = LocateRegistry.createRegistry(1099);
    reg.rebind("myinterfaceimplementacja", ref);
    

    这将在标准端口(1099)上为您创建RMI注册表。如果运行程序,将创建注册表,并以给定名称导出和注册远程对象。

    另一种方式是写

    Registry reg = LocateRegistry.getRegistry();
    

    这使您的程序可以找到已在运行的现有注册表。您必须在运行程序之前启动RMI注册表,方法是调用remiregistry工具,该工具也是JDK的一部分:

    rmiregistry
    

    现在你可以编译并开始你的程序了:

    javac Serwer.java
    java Serwer
    

    它将在注册表中启动并注册您的远程对象实现,使其可供客户端查找。