gpt4 book ai didi

java - 如何从java实例化在scala中定义的嵌套泛型类?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:33:24 24 4
gpt4 key购买 nike

我正在尝试从 Java 实例化一个嵌套的通用 Scala 类并遇到此编译错误。有人可以帮忙吗?谢谢

外部.scala:

class Outer {
class Inner[A]
}

sctest.java:
public class sctest{
public static void main(String[] args) {
Outer o = new Outer();
Outer.Inner<String> a = o.new Inner<String>();
}
}

$ javac sctest.java

sctest.java:4:错误:类 Outer.Inner 中的构造函数 Inner 不能应用于给定类型;
Outer.Inner a = o.new Inner();
^
要求:外
发现:没有参数
原因:实际参数列表和形式参数列表的长度不同
其中 A 是一个类型变量:
在类 Outer.Inner 中声明的扩展对象
1 个错误

最佳答案

我不知道如何从 Java 中完成此操作。详情见附录。我将直接跳到解决方法建议。

每当您在尝试从 Java 调用 Scala 代码时遇到 Java-Scala 互操作问题时,有一个简单但可能有点重量级的解决方法,它基本上适用于所有情况。

TL;博士

如果在 Java 代码中实例化 Scala 实体不起作用,请将所有内容隐藏在 Java 接口(interface)后面,并在 Scala 中实现此接口(interface)。

解决方案建议

如果你使用的是一些主流的 Scala 框架,它可能
有一个完全独立的 Java API(例如 Spark、Akka、Play),那么
请使用它!

如果它是一个鲜为人知的 Scala 软件包,没有单独的
Java API,请执行以下操作:

  • 用纯 Java 编写一个最小的、干净的面向用户的 API
  • 在 Java 中提供面向框架的接口(interface)
  • 在 Scala 中实现 Java 接口(interface)
  • 提供 Java API 实现的入口点
  • 在您的 Java 代码中使用纯 Java API

  • 如果您不想实现完整的 Java API,您可以在本地使用这种方法来处理那些无法与您的 Java 项目无缝协作的 Scala 代码部分。

    为什么它应该起作用:Scala 总是试图适应 Java。
    Java 完全忽略了 Scala。因此,它更容易
    从 Scala 调用 Java 代码,并在 Scala 中实现 Java 接口(interface)
    Scala,而不是相反。

    以下是如何将此模式应用于您的示例(我对其进行了一些扩展以使其不平凡):

    请注意,类名有些难看,我这样做只是为了省略包声明,以便所有文件都可以转储到 src/main/{scala,java};不要在实际实现中这样做。

    步骤 0:看第三方Scala库

    假设这是我们的第三方 Scala 库,
    superImportantMethod s 并计算 superImportantThings :
    /* Suppose that this is the external Scala library 
    * that you cannot change.
    * A = Outer
    * B = Inner
    *
    * + I added at least one member and one
    * method, so that it's not so boring and trivial
    */

    class A {
    var superImportantMemberOfA: Int = 42
    class B[T](t: T) {
    def superImportantMethod: String = t + "" + superImportantMemberOfA
    }
    }

    第 1/2 步:用于 Java 项目的最小 Java API

    我们将在我们的java项目中使用这些接口(interface),并实现它们
    直接使用 Scala:
    interface A_j {
    <X> B_j<X> createB(X x);
    }

    interface B_j<X> {
    String superImportantMethod();
    }

    第 3 步:在 Scala 中实现接口(interface)
    /** Implementation of the java api in 
    * Scala
    */
    class A_javaApiImpl extends A_j {
    private val wrappedA: A = new A

    private class B_javaApiImpl[X](val x: X) extends B_j[X] {
    private val wrappedB: wrappedA.B[X] = new wrappedA.B[X](x)
    def superImportantMethod: String = wrappedB.superImportantMethod
    }

    def createB[X](x: X): B_j[X] = new B_javaApiImpl[X](x)
    }

    第四步:提供 API 的入口点
    /** Some kind of entry point to the 
    * java API.
    */
    object JavaApi {
    def createA: A_j = new A_javaApiImpl
    }

    第五步:在您的 Java 代码中使用仅限 java 的 API:
    public class JavaMain {
    public static void main(String[] args) {

    // Use the Java API in your Java application
    // Notice that now all A_j's and B_j's are
    // pure Java interfaces, so that nothing
    // should go wrong.
    A_j a = JavaApi.createA(); // the only call of a Scala-method.
    B_j<String> b = a.createB("foobarbaz");
    System.out.println(b.superImportantMethod());
    }
    }

    现在应该不会出错,因为 Java(几乎)从不调用任何
    Scala 方法或构造函数,并且通过定义一个干净的 API,您还
    保证您不会遇到任何问题,因为
    一些 Scala 概念无法用 Java 表示。确实如此
    编译并运行:
     [info] Running (fork) JavaMain 
    [info] foobarbaz42

    附录一

    (失败)尝试从 Java 实例化通用内部 Scala 类

    我从这些定义开始(从您的问题中略微缩写的代码):

    .scala:
    class A {
    class B[T]
    }

    .java:
    public class JavaMain {
    public static void main(String[] args) {
    A a = new A();
    A.B<String> b = a.new B<String>(a);
    }
    }

    请注意,javac 编译器需要一个类型为 A 的参数。对于 B构造函数,
    这已经有点可疑,而且不是很直观。

    它编译了,但是当我尝试运行它时,我收到了以下神秘的错误消息:

    [错误] 线程“main”中的异常 java.lang.NoSuchMethodError: A$B.(LA;LA;)V
    [错误] 在 JavaMain.main(JavaMain.java:4)

    我完全不知道这应该是什么意思,所以我反编译了生成的
    “.class”-文件:

    反编译的 A.class:
    public class A {

    public class B<T> {
    public /* synthetic */ A A$B$$$outer() {
    return A.this;
    }

    public B() {
    if (A.this == null) {
    throw null;
    }
    }
    }

    }

    反编译的 A$B.class:
    public class A.B<T> {
    public /* synthetic */ A A$B$$$outer() {
    return A.this;
    }

    public A.B() {
    if (A.this == null) {
    throw null;
    }
    }
    }

    反编译的 JavaMain.class:
    public class JavaMain {
    public static void main(String[] arrstring) {
    A a;
    A a2 = a = new A();
    a2.getClass();
    A.B b = new A.B(a2, a);
    }
    }
    new A.B(a2, a)对我来说,这部分甚至看起来都不像是有效的 java(也不是
    javac)。所以,我本质上想说的是:一切
    崩溃和燃烧,我不知道为什么。因此,我会
    只是建议实现上述解决方法。

    希望有帮助。

    关于java - 如何从java实例化在scala中定义的嵌套泛型类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48835404/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com