【问题标题】:ClassNotFoundException when dynamically calling a Class with forName()使用 forName() 动态调用类时出现 ClassNotFoundException
【发布时间】:2014-09-15 15:53:27
【问题描述】:

我正在尝试在 Eclipse 中动态调用特定的类,特别是 MyClass0

完全限定的类路径存储在String array[] 中,其中索引与多个 MyClass 之一相关,(MyClass0, MyClass1 ... MyClass-nth)。

每个 MyClass 都有相同的方法和数据结构,但具有不同的值。

package forName;

public class Main {

    private static String toMyClassOf_ID[];

    public static void main(String[] args) {
        toMyClassOf_ID = new String[1]; //new String[n];
        toMyClassOf_ID[0] = ("/exampleForName/src/forName/MyClass0.java"); //toClass[ MyClass_ID ]
    /*  .
     *  .
     *  toClass[n] = ...
     */ 
        Class toMyClass;

        try {
            Class cls = Class.forName(toMyClassOf_ID[0]);
            ClassLoader clsLoader = cls.getClassLoader();
            toMyClass= Class.forName(toMyClassOf_ID[0], true, clsLoader);
        } 
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //toMyClass.doMethod(); //commeted to allow run test
    }
}

//---------

package forName;

public class MyClass0 {

    public static void doMethod() {
        System.out.println("success");
    }
}

问题:

  • 我收到"java.lang.ClassNotFoundException"

问题:

  • forName() 是正确的方法吗?
  • 我是否拥有正确的完全限定类路径toMyClassOf_ID[0],才能使其正常工作?例如("/exampleForName/src/forName/MyClass0.java")
  • 如果不正确,使用什么格式?如何找到它?

【问题讨论】:

  • 尝试使用“.”作为分隔符而不是“/”。
  • Class.forName() 适用于 class 文件,不适用于 source 文件
  • /exampleForName/src/forName/MyClass0.java 是一个源文件。它必须先编译并加载到Classloader 中,然后才能加载。然后您需要使用forname.MyClass0 来调用Class.forName

标签: java eclipse class dynamic


【解决方案1】:

如前所述

Class.forName()

接受类的完全限定名称,即包声明中给出的包名称,在您的情况下为“forName”,后跟一个点,后跟类声明中给出的类名称,在你的情况下“MyClass0”。 所以工作示例是

Class<?> cls = Class.forName("forName.MyClass0");

您不能像尝试那样使用源文件的路径。

但是阅读的时候

每个 MyClass 都有相同的方法和数据结构,但具有不同的值。

我不确定这是否真的是你应该或想要做的。

听起来你最好有一个类“MyClass”,其中包含实例方法和实例字段以及预定义实例列表。

如果您想这样做,您可以静态初始化这些实例:

public MyClass {
  public static final MyClass[] instances;
  static {
    instances = new MyClass[1];
    instances[0] = new MyClass();
    instances[0].myField = "value1";
  }

  private String myField;
  public void doMethod()
  {
    ...
  }
}

当然,您可以使用其他机制来创建这些实例,例如工厂方法或依赖注入。

你说每个 MyClass 都有不同的值。如果您还需要每个 MyClass 具有不同的 doMethod(或任何其他方法)实现,则应使用 MyClass 作为基类并实现从 MyClass 扩展的子类。

public class MyClass0 extends MyClass
{
  @Override
  public void doMethod()
  {
    // different implementation
  }
}

你可以再次使用静态初始化:

public class MyClass
{
  public static final MyClass[] instances;
  static {
    instances = new MyClass[1];
    instances[0] = new MyClass0();
    instances[0].myField = "value1";
  }
  ...
}

当然,现在您有从基类到子类的依赖关系,这通常不是一个好主意,但我认为这是解决您问题的直接解决方案。

【讨论】:

  • 哦,谢谢,看来它对我正在做的事情有用。我是 java 新手,所以我错过的东西对某些人来说似乎很简单。目前我在源代码中有类和方法,但是让程序创建类并将值放在那里听起来更传统。
  • "如果你还需要每个 MyClass 都有不同的 doMethod 实现" 我不知道方法基本上只是获取.. 调用类数据
  • 嗨,感谢 cmets 和帮助。我不确定哪个是这个答案的最佳解决方案,并且说使字符串“forName.MyClass0”的答案也有效。我想我首先尝试的方式更像是 C++ 风格,因为字符串就像一个头文件。第一种方法 - 我确实必须使用方法调用来调整它以匹配 forName()。但同样两者都成功了。
【解决方案2】:

除了可怕的命名等,这是错误的:

"/exampleForName/src/forName/MyClass0.java"

你需要:

"forName.MyClass0"

【讨论】:

    【解决方案3】:

    Class.forName 不是在等待文件的路径,而是在等待完整的类名(即不带 .java 扩展名的包 + 类名):forName.MyClass0

    【讨论】:

      【解决方案4】:

      指定 .java 文件的路径是不对的

      你应该有你的java文件的.class文件来使用Class.forName

      参考http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String)

      【讨论】:

        【解决方案5】:

        您必须将 FQCN(Fully Qualified Class Name) 作为参数传递给 forName,而您指定的 .java 文件的路径不正确。

        更改以下行

        toMyClassOf_ID[0] = ("/exampleForName/src/forName/MyClass0.java");
        

        必须改为-

        toMyClassOf_ID[0] = "forName.MyClass0"; //Fully Qualified Class Name in java package notation
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-05-17
          • 2013-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多