代码之家  ›  专栏  ›  技术社区  ›  Amir Afghani

为什么在使用Class.forName(…)时会得到ClassNotFoundException?

  •  2
  • Amir Afghani  · 技术社区  · 14 年前

    在下面的例子中,我试图使用 sun.tools.javac.Main 动态编译我生成的类,然后实例化该类的对象并调用方法。到目前为止,我甚至无法通过加载生成的类。我在Eclipse中得到以下异常:

    java.lang.ClassNotFoundException: TestHello_1289950330167
        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.ClassLoader.loadClassInternal(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at MyClassGenerator.runIt(MyClassGenerator.java:47)
        at MyClassGenerator.main(MyClassGenerator.java:13)
    Note: sun.tools.javac.Main has been deprecated.
    1 warning
    Running TestHello_1289950330167:
    

    代码如下:

    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileWriter;
    import java.net.URL;
    import java.net.URLClassLoader;
    
    public class MyClassGenerator {
        String generatedClassName = "TestHello_" + System.currentTimeMillis();
        String javaFileName = this.generatedClassName + ".java";
    
        public static void main(final String args[]) {
            final MyClassGenerator mtc = new MyClassGenerator();
            mtc.createIt();
            if (mtc.compileIt()) {
                System.out.println("Running " + mtc.generatedClassName + ":\n\n");
                mtc.runIt();
            }
            else {
                System.out.println(mtc.javaFileName + " is bad.");
            }
        }
    
        public void loadIt() {
    
            final ClassLoader classLoader = MyClassGenerator.class.getClassLoader();
    
            try {
                final Class aClass = classLoader.loadClass(this.generatedClassName);
                System.out.println("Loaded " + aClass.getName());
            }
            catch (final ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    
        public void createIt() {
            try {
                final FileWriter aWriter = new FileWriter(this.javaFileName, true);
                aWriter.write("public class " + this.generatedClassName + " { }");
                aWriter.flush();
                aWriter.close();
            }
            catch (final Exception e) {
                e.printStackTrace();
            }
        }
    
        public boolean compileIt() {
            final String[] source = { new String(this.javaFileName) };
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
            new sun.tools.javac.Main(baos, source[0]).compile(source);
    
            System.out.print(baos.toString());
    
            return (baos.toString().indexOf("error") == -1);
        }
    
        public void runIt() {
            try {
                final File file = new File(this.javaFileName);
                final URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL() });
                final Class<?> cls = Class.forName(this.generatedClassName, true, classLoader);
            }
            catch (final Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    2 回复  |  直到 13 年前
        1
  •  6
  •   BalusC    14 年前

    因为它不在类路径中。将其写入类路径(或将其根路径添加到类路径)或使用 URLClassLoader .

    File root = new File(".");
    URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
    Class<?> cls = Class.forName(generatedClassName, true, classLoader);
    

    在中使用相对路径 java.io 顺便说一下是个坏主意。您所依赖的当前工作目录在代码中是不可控制的。

        2
  •  1
  •   mhaller    14 年前

    你正在创建一个新的 URLClassLoader 指向一个具体的文件。以命令行参数表示,您这样做:

    java -cp file:///foo/bar/TestHello_1289950330167.java
    

    然后你的代码调用这个:

    Class.forName("TestHello_1289950330167",true,cl);
    

    类路径是JAR文件或 文件夹 ,不是.java文件!

    您应该做的是使用 ".".toURI().toURL() 作为类路径,而不是 javaFileName .