Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/400.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Java调用多态Scala方法_Java_Scala_Interop_Polymorphism - Fatal编程技术网

从Java调用多态Scala方法

从Java调用多态Scala方法,java,scala,interop,polymorphism,Java,Scala,Interop,Polymorphism,我正在编写一个API,我希望它可以从Scala和Java中使用。我在Scala类中定义了一个多态方法,从Java调用它时遇到了问题 根据scala-lang.org上的这种互操作性,使用使用使用高级语言功能的scala类“可能很棘手”,但它并没有说这是不可能的。由于Scala的高级特性如何转换为Java没有文档记录,因此建议分解类文件以试验其工作方式 示例代码 class Polymorphic { def polyMethod[T](implicit om: Manifest[T]) =

我正在编写一个API,我希望它可以从Scala和Java中使用。我在Scala类中定义了一个多态方法,从Java调用它时遇到了问题

根据scala-lang.org上的这种互操作性,使用使用使用高级语言功能的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
三大问题:

  • 该方法的返回类型是多态的
  • Manifest
    参数在Java中不是隐式的
  • 我实际上无法传递类型参数
  • 我尝试使用的真正项目代码如下:

    我的最终目标是一个完全通用但类型安全的数据字典。它在Scala中工作得很好,但我真的希望能够从JavaAPI调用这个方法。我的设计动机是保留客户机代码中的反射、显式转换和空检查

    编辑:2011年11月18日回复@kassens以下评论

    polyMethod
    的定义更改为以下内容:

    def polyMethod[T](implicit om: Manifest[T]): T = {
      println(om.erasure.getName)
      om.erasure.newInstance.asInstanceOf[T]
    }
    

    当我使用
    javap

    检查类文件时,给出了完全相同的字节码一个建议是使用Java泛型类型,并对自己的数据类型进行装箱/取消装箱。使用类型匹配来执行您的操作。

    在java中,拥有清单参数的等效方法是传递类(显式地,当您想要的类型是泛型类型时,它不会工作得太好)

    可以从java创建清单,但最好从scala创建清单。 你可以加上

    def polyMethodForJava[T](clazz: Class[T]) 
      = polyMethod(ClassManifest.From(clazz))
    

    当然,使用它不会像在scala中那样舒服。

    当然有一些scala方法不能从Java调用。有关一个示例(不是您遇到的示例)的描述,请参阅


    一般来说,如果您想创建一个Java客户端“自然”使用的接口,您可能需要编写一些适配器类或方法。

    有几个问题:

  • Scala中的统一泛型。事实上,
    T
    在Scala中是无界的(这意味着它可以用基元类型实例化),这使得Scala编译器保守地将其擦除到
    对象
    。如果将scala代码更改为

    def polyMethod[T <: AnyRef](implicit om: Manifest[T]) = {
       println(om.erasure.getName)
       om.erasure.newInstance.asInstanceOf[T]
    }
    
    然后从Java中这样称呼它:

    void test(Polymorphic p) { 
        JavaScalaCall c = p.polyMethod(this.getClass());
    }
    

    作为旁注,字节码总是被擦除的。如果您想查看类文件中的通用信息,请使用签名属性,例如,.

    Hmm--
    @bridge
    注释非常酷,我可能最终会使用它。在这一点上,让它工作的魔法胶水似乎不会像纯Scala API那么漂亮,我宁愿不污染它。谢谢,你能解释一下你的意思吗?请参考这个Java Box/Unbox页面:我了解Java中拳击的工作原理,但我不知道它在这种情况下有什么帮助。抱歉,也许我遗漏了一些东西。事实上,我考虑的另一种方法是在标准库中发现的分散的方法:接受虚拟原型对象作为参数。无论如何,调用站点代码的作者仍然有责任明确地正确地转换结果。也许这是Java语言目前存在的一个不可避免的缺陷。该方法的返回类型不是多态的。静态返回类型为
    Any
    :@kassens:谢谢。我对你的评论进行了编辑,但我认为这并不是根本问题。只是一个评论,如果你想看很多字节码,请看JAD:它将java作为输出
    void test(Polymorphic p) { 
        JavaScalaCall c = p.polyMethod(this.getClass());
    }