使用反射Java的`newInstance`实例化Scala类

时间:2013-07-01 09:51:13

标签: java scala

对于某些特殊用例,我有一个小实用程序,可以使用动态类加载器DynamicClassLoader从jar加载Java类。这适用于jar中包含的Java类。从jar加载Scala类也可以正常工作。但是,实例化加载的Scala类会导致以下异常。看起来Scala类有私有默认构造函数?请注意编译的Scala类名称以$

结尾
java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"

下面的代码段说明了我想要实现的目标并提供更多背景信息。例外情况发生在带注释的行:

// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");

DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens 
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();

任何想法如何解决?

1 个答案:

答案 0 :(得分:5)

显然,您需要将默认构造函数设置为public(对于没有公共默认构造函数的Java类,它也不起作用)。 E.g。

class ScalaClassYYY() {
  ...
}

或者如果你想让主构造函数接受一些参数,

class ScalaClassYYY(arg1: Int) {
  def this() = this(0)
}

但是来自

  

请注意编译的Scala类名称以$

结尾

看起来您实际上正在尝试实例化Scala object

object ScalaClassYYY { ... }

在这种情况下,您不应创建新实例,而应使用the existing one

(IRegisterExecutor) registerClass.getField("MODULE$").get(null);

编辑:

  

我在你的回答中没有看到你如何将一个默认的公共构造函数添加到不需要任何参数的Scala类中。

不需要任何参数的class object)已经有一个默认的公共构造函数(我的第一个例子)。

  

实际上在Java中,默认情况下所有类都提供公共默认构造函数

没有。只有那些没有构造函数的类才能接受参数。

  

删除“(对于没有公共默认构造函数的Java类也不行)”因为它错了

documentation for Class.newInstance()

  

IllegalAccessException - 如果无法访问该类或其无效构造函数。

所以我很确定这是对的。如果它对没有公共默认构造函数的Java类有效,那么这似乎是您使用的类加载器中的一个主要错误。您可以使用类似于以下内容的Java类对其进行测试:

public class TestClass implements IRegisterExecutor {
    public TestClass(int dummy) {}

    // some implementation for IRegisterExecutor methods to get it to compile
}