如何仅使用零参数构造函数通过 Java 反射创建具有上下文绑定的 Scala 类的新实例? [英] How to create new instance of Scala class with context bound via Java reflection using only zero argument constructor?

查看:44
本文介绍了如何仅使用零参数构造函数通过 Java 反射创建具有上下文绑定的 Scala 类的新实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 Scala 编写客户端代码,需要与 Java 框架进行交互.该框架负责创建通过 API 指定的类的对象实例,它使用反射来实现.例如:

I am writing client code in Scala that needs to interface with a framework in Java. The framework is responsible for creating object instances of classes specified via an API, which it does using reflection. For example:

public class ReflectionUtil {

  public static <T> T newInstance(Class<T> aClass) {
    T result;
    try {
      Constructor<T> meth = aClass.getDeclaredConstructor(new Class[]{});
      meth.setAccessible(true);
      result = meth.newInstance();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return result;
  }
}

我想要创建的对象实例的类是在 Scala 中实现的,并在一个具有上下文绑定的类型上参数化.例如:

The classes of the object instances I want to create are implemented in Scala and are paramerterised on a type that has a context bound on it. For example:

class OrderedValue[A](var value: A)(implicit ord: Ordering[A]) {
  def get: A = value
  def set(x: A) = { value = x }
  def cmp(that: OrderedValue[A]): Int = ord.compare(this.value, that.value)
}

当我将此类传递给 Java 框架以构造新实例时,我遇到了一个问题,因为该框架假设该类将具有可用的零参数构造函数.例如,以下代码将导致 newInstance 中的 NoSuchMethodException:

I run into a problem when I pass this class to the Java framework to construct new instances as the framework makes the assumption that the class will have a zero-argument constructor available. For example, the following code will result in a NoSuchMethodException from within newInstance:

def main(args: Array[String]) {

  val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
  val b: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])

  a.set(3)
  b.set(5)

  println(a.cmp(b))
}

尝试解决此问题是向 OrderedValue 添加零参数构造函数,但是隐式参数 ord 没有合理的值.将其设置为 null 将导致 cmp 中的 NullPointerException:

An attempt at resolving this issue is to add a zero-argument constructor to OrderedValue however there is no reasonable value for the implicit parameter ord. Setting it to null will result in a NullPointerException within cmp:

def this() = this(null.asInstanceOf[A])(null.asInstanceOf[Ordering[A]])

另一种方法是对 OrderedValue 的特定具体值进行子类化.例如:

Another approach is to subclass a particular concrete value of OrderedValue. For example:

class OrderedIntValue(val v: Int) extends OrderedValue[Int](v) {
  def this() = this(null.asInstanceOf[Int])
}

val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])

这可行,但并不理想,因为知道OrderedValue 的具体类型并不总是方便或不可能.例如,newInstance 可能在一个范围内被调用,该范围也被参数化为一个类型(即我们不知道它具体是一个 Int).

This will work but is not ideal as it is not always convenient or possible to know the concrete type of OrderedValue. For example, newInstance may be called within a scope that is also parameterised on a type (i.e. we don't know that it's specifically an Int).

所以我的问题是:鉴于上下文边界(即类型类)是 Scala 中一个非常有用且现在常用的特性,并且鉴于我无法更改与我交互的 Java 框架的内部结构,有有没有人遇到或开发出一种方法可以让这一切都奏效?

So my question is: given that context bounds (i.e. type classes) are a very useful, and now commonly used, feature within Scala, and given I can not change the internals of the Java framework that I am interfacing with, has anyone encountered or developed an approach that can make this all work?

推荐答案

隐式参数由 Scala 编译器在编译时填充.如果要使用反射实例化类,则必须手动指定这些参数.没有办法解决它.因此,您可以使用上下文边界或无参数构造函数.

Implicit arguments are filled in by the Scala compiler at the compile time. If you want to instantiate classes using reflection you will have to specify those arguments manually. There is just no way around it. So you can either have context bounds or no-argument constructors.

这篇关于如何仅使用零参数构造函数通过 Java 反射创建具有上下文绑定的 Scala 类的新实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆