我正在编写一个我希望可以在Scala和Java中使用的API。我在Scala类中定义了一个多态方法,但在从Java调用它时遇到了麻烦。
根据scala-lang.org上的互操作性FAQ,使用使用高级语言功能的Scala类“可能会很棘手”,但这并不是说不可能。由于未记录Scala的高级功能如何转换为Java,因此建议拆开类文件以试验其工作方式。
范例程式码
class Polymorphic {
def polyMethod[T](implicit om: Manifest[T]) = {
println(om.erasure.getName)
om.erasure.newInstance
}
}
object Polymorphic {
def main(args: Array[String]) {
val objOfT = (new Polymorphic).polyMethod[String]
}
}
在scala中工作正常,打印“
java.lang.String
”我在生成的类文件上运行了
javap -c
,并获得了polyMethod
的以下列表:public java.lang.Object polyMethod(scala.reflect.Manifest);
Code:
0: getstatic #20; //Field scala/Predef$.MODULE$:Lscala/Predef$;
3: aload_1
4: invokeinterface #27, 1; //InterfaceMethod scala/reflect/ClassManifest.erasure:()Ljava/lang/Class;
9: invokevirtual #33; //Method java/lang/Class.getName:()Ljava/lang/String;
12: invokevirtual #37; //Method scala/Predef$.println:(Ljava/lang/Object;)V
15: aload_1
16: invokeinterface #27, 1; //InterfaceMethod scala/reflect/ClassManifest.erasure:()Ljava/lang/Class;
21: invokevirtual #41; //Method java/lang/Class.newInstance:()Ljava/lang/Object;
24: areturn
3个主要问题:
该方法的返回类型是多态的
Manifest
参数在Java中不是隐式的我实际上无法传递type参数。
我正在尝试使用的真实项目代码在这里:
https://github.com/ConnorDoyle/EnMAS/blob/master/clientServerPrototype/src/org/enmas/pomdp/State.scala
我的最终目标是建立一个完全通用但类型安全的数据字典。它在Scala中很好用,但是我也很想能够从Java API调用此方法。我的设计动机是使反射,显式强制转换和null检查保持在客户端代码之外。
编辑:2011年11月18日回应以下@kassens的评论
将
polyMethod
的定义更改为以下内容:def polyMethod[T](implicit om: Manifest[T]): T = {
println(om.erasure.getName)
om.erasure.newInstance.asInstanceOf[T]
}
当我用
javap
检查类文件时,给出了完全相同的字节码。 最佳答案
有几个问题在起作用:
Scala中的统一泛型。 T
在Scala中是不受限制的(意味着可以使用原始类型实例化),这使得Scala编译器保守地将其擦除为Object
。如果您将Scala代码更改为
def polyMethod[T <: AnyRef](implicit om: Manifest[T]) = {
println(om.erasure.getName)
om.erasure.newInstance.asInstanceOf[T]
}
它会返回T。请注意从
newInstance
进行的显式强制转换,因为Scala库方法未返回正确的泛型类型。使用清单。这将添加另一层泛型,您需要对其进行对齐才能通过呼叫。正如Didierd建议的那样,最好在Scala中使用一个
java.lang.Class
代替。因此,我的建议是将其添加到您的Scala代码中:
def polyMethod[T <: AnyRef](cls: Class[T]): T =
polyMethod(Manifest.classType(cls))
然后从Java以这种方式调用它:
void test(Polymorphic p) {
JavaScalaCall c = p.polyMethod(this.getClass());
}
附带说明,字节码始终被擦除。如果要在类文件中查看常规信息,请使用例如jclasslib查找Signature属性。
关于java - 从Java调用多态Scala方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8171770/