从 Java 代码访问 Scala 类型 Class?

Accessing Scala Type Class from Java code?

我使用类型 classes 和临时多态性在 Scala 中创建了许多不同的拍卖实现。

可以找到 Scala 实现的示例 here

在 Scala 中创建一个拍卖实例如下...

val google: GoogleStock = GoogleStock(tick=1)
val pricingRule = new MidPointPricingPolicy[GoogleStock]
val withDiscriminatoryPricing = OpenBidDoubleAuction.withDiscriminatoryPricing(pricingRule)

我希望用户能够从 Java 8.

访问拍卖实施

但我似乎无法弄清楚如何在 Java 中创建拍卖实例。采用这种方法:

MidPointPricingPolicy<GoogleStock> midPointPricing = new MidPointPricingPolicy<GoogleStock>();
OpenBidDoubleAuction.DiscriminatoryPricingImpl<GoogleStock> auction = OpenBidDoubleAuction$.MODULE$.withDiscriminatoryPricing(midPointPricing);

有效,但 none 类型的 class 合同方法可用。具体来说:

OpenBidDoubleAuction.DiscriminatoryPricingImpl<GoogleStock> auction2 = auction.insert(order3);

...产生以下编译错误。

Error:(90, 82) java: cannot find symbol
symbol:   method insert(org.economicsl.auctions.singleunit.orders.LimitAskOrder<org.economicsl.auctions.GoogleStock>)
location: variable auction of type org.economicsl.auctions.singleunit.twosided.SealedBidDoubleAuction.UniformPricingImpl<org.economicsl.auctions.GoogleStock>

似乎在编译 Java 代码时,Scala 编译器为类型 class 生成的契约方法不可用。在我的 build.sbt 文件中,我设置了 compileOrder := CompileOrder.ScalaThenJava 以确保首先编译这些 Scala,以便这些方法可用。

根据@GhostCat 的建议,我使用 javap 发现 Scala 编译器生成了以下 .class 文件...

OpenBidDoubleAuction$DiscriminatoryPricingImpl$$anon.class

其中包含相关方法的字节码定义。

所以我想我需要知道如何从 Java 访问此字节代码文件中定义的内容?有可能吗?

一般的答案是:那是两种不同的语言。在 java 端 visible 的唯一东西是 bytecode 中为 OpenBidDoubleAuction 找到的元素。

因此:您计算 "what can I use from Java" 的一种可能方法:转到 javap 并检查 scalac 生成的字节码。这将告诉您所有可用的方法及其签名。如果你发现你的 "enhanced" 例子太复杂了:退后一步。创建一个 minimal 示例 - 一小块 scala;然后仔细分析生成的字节码。

当然:您首先要检查 documentation - 您希望避免将时间浪费在根本不可能的事情上。从事物的 Java 方面来看,您不能使用各种语言元素。

(请注意:link 已过时,但可能足以作为您自己研究的起点)

Java 没有 implicit 关键字,也不知道任何关于隐含的东西。 implicit def 到 Java 只是另一种方法。因此,当您从 Java 调用此代码时,您必须显式添加所有隐式转换和隐式参数。如果你想知道那会是什么样子,你可以打开一个 Scala REPL 并使用 //print <tab> 提示来查看你的代码在经过几次脱糖和显式隐含后会是什么样子。

例如,给定一些类型类 Foo 和隐式 FooSyntax:

scala> 42.foo //print <tab>
   FooSyntax[Int](42)(Foo.fooInt).foo // : String

明确地说,在它说 <tab> 的地方,您必须按 Tab 键而不是键入它:)

然后,如果你有点幸运,你所要做的就是将脱糖的 Scala 进一步转换为实际的 Java:

FooSyntax(42, Foo.fooInt()).foo();

如果您不那么幸运,您可能需要添加一些额外的 MODULE$ 内容。如果您 甚至更少 幸运并且您必须与结构类型或交叉类型之类的东西进行互操作,那么您可能必须分别使用反射或转换。

但一般来说:如果您想从 Java 调用相同的代码,不要 使用 Scala 的高级功能,如类型类。如果您必须创建一个可从 Java 调用的库,那么尝试编写(在 Scala 中)Java 友好的包装器 advanced/incompatible 部分。