如何从scala中的子类调用超类构造函数以及如何进行构造函数链接

时间:2016-07-02 13:56:27

标签: scala

我正在尝试下面的java代码在scala中转换它但我无法从scala中的子类调用超类构造函数。我该如何解决这个问题。

//java code
class A
{
    public A(String a){}
    public A(String a, int b){}
}
class B extends A
{
    public B(String c){
        super(c);
    }
    public B(String c,int d){
        super(c,d);//how to do this in scala
    }
}

1 个答案:

答案 0 :(得分:11)

您将从构造函数的一些基本scala教程中受益,但让我试试。 简而言之 - 你不能完全在scala中这样做。

  1. 与Java不同,在Scala中有一个“主要”构造函数,所有其他构造函数最终必须链接到它。如果你的主要构造函数定义为class Foo(x: Int, y: Int, s: String) extends Bar(s),你可以在Foo中定义另一个构造函数,但它必须链回到它的主构造函数def this(x: Int) = this(x, 0, "")
  2. 在Scala中,表达调用超级构造函数的方式是在类定义的extends Bar(...)部分中(因此,您只能将其作为定义主构造函数和类的一部分)。使用与上面相同的示例,如果您有class Bar(s: String)并且扩展它class Foo(val x: Int, val y: Int, s: String) extends Bar(s),则在声明要扩展它的同时调用超级构造函数,即{{1} } part。
  3. 因此,鉴于上述两点,由于所有构造函数必须链接到类的单个主构造函数并且单个主构造函数仅调用单个超级构造函数,因此无法在Scala中完全转换Java示例。但是,你可以通过这样做获得相同的东西。

    extends Bar(s)

    实际上,在scala中你首先链接,然后应用所有默认值,然后你调用super而不是像你在Java中那样从你的各种构造函数调用super。

    您可以将超级构造函数默认值存储在随附final class Foo(x: Int, y: Int, s: String) extends Bar(s) { def this(x: Int) = this(x, 1/*Foo's default*/, ???/*you likely want the same default that super would use, in this case "bar", see below*/) } class Bar(s: String) { def this() = this("bar") } 中,并在object Bar { defaultString: String = "bar" }Foo中使用它,以确保impl保持同步。这看起来很笨重,但实际上更安全,因为它确保了相同的行为,无论你调用哪个构造函数,而在java中你可能有不同的默认值(这将是有问题的)。这是:

    Bar

    但请注意,在scala中 - 由于已建立的伴随对象和应用方法的设施(您可以将它们视为Java中的静态工厂方法),我不会看到人们使用大量非主要构造函数。它们使用了几种final class Foo(x: Int, y: Int, s: String) extends Bar(s) { def this(x: Int) = this(x, 1/*Foo's default*/, Bar.defaultString) } class Bar(s: String) { def this() = this(Bar.defaultString) } object Bar { protected val defaultString: String = "bar" } 方法,因此您的主构造函数通常会获取所有可能的参数。另一种选择是让它们使用默认值。因此,您很少需要非主要构造函数和链接。

    在相关的说明中,如果您有直接传递给超类的构造函数参数,请注意不要包含apply,因为这会复制子类中的变量,并增加内存占用量。这有点微妙。另外,如果您碰巧在主ctor中引用了一个在其前面没有val的变量,但是从超类中看不到它,编译器将假设它具有val修饰符并且还将保存它作为子类中的一个字段。让我来说明一下

    private[this] val

    由于我提到的是出现在B的构造函数中的class A(val name: String, val counter: Int) class B( val b: Int /*this is B's field by design*/, str: String/*meant to be passed to super, so no val*/, i: Int /*meant to be passed to super, so no val*/) extends A(str, i) { def firstLetterOfName = str.head // Oops, I should have done name.head } 而不是str这是A的字段,name将获得默认的str修饰符,并将保存为{ {1}}也是字段,因此复制了超类private[this] val中的B字段。现在我们有两个重复的字段。