我正在编写一个我希望可以在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/

10-11 23:13
查看更多