17

我有一个Scala课程:

class Foo(val x:String = "default X", val y:String = "default Y" ) 

我想从Java调用它,但使用默认参数

通过null不起作用(它null按预期分配)

new Foo(null,null); //both are instantiated as null

这个技巧确实对我有用,但它很难看,我想知道是否有更好的方法:

斯卡拉

class Foo(val x:String = "default X", val y:String = "default Y" ) {
  def this(x:Object) = this()
}

爪哇

new Foo(null); //no matter what I pass it should work

但是我想摆脱构造函数重载技巧,并使用 0 参数构造函数

那可能吗?

4

3 回答 3

7

看来,没有这样的方式:https ://issues.scala-lang.org/browse/SI-4278

问题:应该为具有所有可选参数的类生成默认的无参数构造函数
......

Lukas Rytz:关于语言统一性,我们决定不修复这个问题——因为这是与框架的互操作性问题,我们认为不应该在语言级别修复它。

解决方法:重复一个默认值,或抽象一个,或将一个默认值放入零参数构造函数

然后 Lukas 提出了与您发现的相同的解决方案:

class C(a: A = aDefault, b: B = C.bDefault) {
  def this() { this(b = C.bDefault) }
}
object C { def bDefault = ... }

// OR

class C(a: A = aDefault, b: B) {
  def this() { this(b = bDefault) }
}
于 2012-10-25T00:20:52.063 回答
3

有一个解决方案,请查看文章中的“默认参数”部分:https ://lampwww.epfl.ch/~michelou/scala/using-scala-from-java.html

可以通过使用 .$default$[number] 格式从 java 传递适当的位置参数来调用构造函数和方法。

这里的范围如下:

  • 类构造函数:<< ClassName >>.init$default$1 为构造函数定义中设置的第一个参数的默认值 default$2 为第二个参数的默认值,依此类推。
  • 方法调用:object.methodName$default$1 来解析方法第一个参数在方法签名中分配的默认值等。

例子:

import za.co.absa.spline.core.SparkLineageInitializer;
SparkLineageInitializer.SparkSessionWrapper lineage = SparkLineageInitializer.SparkSessionWrapper(spark);
lineage.enableLineageTracking(lineage.enableLineageTracking$default$1());

对于此示例,maven 依赖项为: groupId: za.co.absa.spline artifactId: spline-core version: 0.3.1

于 2018-10-18T21:24:30.383 回答
2

更一般地,如果您有一个带有默认参数的 Scala 类,并且您想在 Java 中实例化覆盖 0、1 或更多默认值而不必指定所有,请考虑扩展 Scala API 以在伴随对象中包含一个 Builder。

case class Foo(
  a: String = "a",
  b: String = "b",
  c: String = "c"
)

object Foo {
  class Builder {
    var a: String = "a"
    var b: String = "b"
    var c: String = "c"
    def withA(x: String) = { a = x; this }
    def withB(x: String) = { b = x; this }
    def withC(x: String) = { c = x; this }
    def build = Foo(a, b, c)
  }
}

public class App {
    public static void main(String[] args) {
        Foo f = new Foo.Builder()
            .withA("override a")
            .build();
    }
}
于 2017-02-18T01:51:18.270 回答