我正在用Scala编写需要与Java框架接口的客户端代码。框架负责创建通过API指定的类的对象实例,这是使用反射来完成的。例如:
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中实现的,并在具有上下文绑定的类型上参数化。例如:
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
:
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
:
def this() = this(null.asInstanceOf[A])(null.asInstanceOf[Ordering[A]])
另一种方法是子类化OrderedValue
的特定具体值。例如:
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
)。
所以我的问题是:考虑到上下文边界(即类型类)是Scala中非常有用的,现在常用的功能,并且考虑到我不能改变与之接口的Java框架的内部,有人遇到或开发出可以使这一切工作的方法吗?
隐式参数由Scala编译器在编译时填充。如果您想使用反射实例化类,则必须手动指定这些参数。这是没有办法的。所以你可以有上下文边界或者无参数构造函数
我发现从Java调用Scala代码最简单的方法是编写一个中间的Scala层,其中包含Scala等效的pojo。没有隐式,签名中没有闭包,没有Companion对象,没有复杂的类型推断等(当然,您可以在内部使用这些)。我还尝试用java替换签名中的大多数scala集合类型。util集合。
是的,它是丑陋的,乏味的,不是很灵活,但至少它从Java端消除了许多语法噩梦。