如何从Java实例化Scala中定义的嵌套泛型类?

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

 

external.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: error: constructor Inner in class Outer.Inner cannot be applied to given types;
    Outer.Inner a = o.new Inner();
                              ^
  required: Outer
  found: no arguments
  reason: actual and formal argument lists differ in length
  where A is a type-variable:
    A extends Object declared in class Outer.Inner
 1 error

最佳答案

我看不到如何用Java做到这一点.有关详细信息,请参见附录.我将直接跳至变通方案.

 

每当尝试从Java调用Scala代码时遇到Java-Scala互操作的问题时,都有一个简单的,虽然可能是重量级的解决方法,但它基本上可以在每种情况下使用.

TL; DR

如果无法在Java代码中实例化Scala实体,则将所有内容隐藏在Java接口之后,并在Scala中实现此接口.

解决方法提案

如果您使用一些主流的Scala框架,则可能
具有完全独立的Java API(例如Spark,Akka,Play),然后
请使用它!

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

>用纯Java编写最小的,干净的面向用户的API
>用Java提供面向框架的接口
>在Scala中实现Java接口
>提供Java API实现的入口点
>在Java代码中使用纯Java API

如果您不想实现完整的Java API,则可以在本地使用此方法来处理Scala代码中与Java项目无法无缝配合的部分.

为何起作用:Scala始终尝试适应Java.
Java完全忽略Scala.因此,这更容易
从Scala调用Java代码,并在其中实现Java接口
Scala,比其他方法要好.

这是将这种模式应用于您的示例的方式(我对其进行了扩展以使其变得平凡):

注意,类名有些丑陋,我这样做只是为了省略包声明,这样所有文件都可以转储到src / main / {scala,java};中.请勿在实际实现中执行此操作.

步骤0:查看第三方Scala库

假设这是我们的第三方Scala库,
具有superImportantMethods并计算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项目中使用这些接口,并实现它们
直接使用Scala:

 

interface A_j {
  <X> B_j<X> createB(X x);
}

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

步骤3:在Scala中实现接口

 

/** 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)
}

步骤4:提供API的入口点

 

/** Some kind of entry point to the 
  * java API.
  */
object JavaApi {
  def createA: A_j = new A_javaApiImpl
}

步骤5:在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编译器要求B构造函数使用类型为A的参数,
已经有些可疑了,不是很直观.

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

[错误]线程“主”中的异常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);
    }
}

新的A.B(a2,a)
对我来说,部分甚至看起来都不像有效的Java(而且对
javac).所以,我本质上想说的是:一切
崩溃和烧伤,我不知道为什么.因此,我会
只需建议实施上述解决方法.

希望能有所帮助.


Inm小程序商店

 

Inm小程序商店收录了最新,最热门的微信小程序和微信小游戏,是国内内容最丰富的集小程序游戏、小程序分发、小程序推广为一体的综合性小程序门户网站之一。


Vultr中文网

 

最低 $2.5/月 的VPS, 稳定, 可靠

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值