我正在尝试下面的Java代码在scala中将其转换,但是我无法从scala的子类中调用父类(super class)构造函数。我该如何解决这个问题。
//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
}
}
最佳答案
您会从一些有关构造函数的基本scala教程中受益,但让我尝试一下。
简而言之-您无法在scala中完全做到这一点。
class Foo(x: Int, y: Int, s: String) extends Bar(s)
,则可以在Foo中定义另一个构造函数,但是它必须像def this(x: Int) = this(x, 0, "")
那样回链到其主要构造函数extends Bar(...)
部分中(因此,在定义主构造函数和类的过程中,您只能执行一次此操作)。使用与上述相同的示例,如果您具有class Bar(s: String)
并将其扩展为class Foo(val x: Int, val y: Int, s: String) extends Bar(s)
,则在声明要扩展它的同时调用 super 构造函数,即extends Bar(s)
部分。 因此,鉴于上述两点,由于所有构造函数都必须链接到类的单个主要构造函数,并且该单个主要构造函数仅调用单个 super 构造函数,因此您无法在Scala中准确地翻译Java示例。但是,您可以通过执行此操作获得等效的结果。
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")
}
实际上,在scala中,您首先要进行链接,并在应用过程中应用所有默认值,然后再调用super而不是像在Java中那样从各种构造函数版本中调用super。
您可以将 super 构造函数的默认值存储在伴随的
object Bar { defaultString: String = "bar" }
中,并在Foo
和Bar
中使用该默认值,以确保impl保持同步。这似乎很笨拙,但实际上更安全,因为无论您调用哪个构造函数,它都能确保相同的行为,而在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"
}
但是请注意,在scala中-由于伴随对象和应用方法的建立良好的设施(您可以将它们视为Java中的静态工厂方法),因此我看不到人们使用很多非主要的构造函数。他们改用几种
apply
方法,因此您的主要构造函数通常采用所有可能的参数。另一种选择是让它们使用默认值。因此,您很少需要非主要构造函数和链接。与此相关的是,如果您具有直接传递给您的父类(super class)的构造函数参数,请注意不要包含
val
,因为这也会在子类中复制该变量,并增加您的内存占用量。这有点微妙。此外,如果您碰巧在主ctor中引用的变量前没有val,但在父类(super class)中不可见,则编译器将假定该变量具有private[this] val
修饰符,并将其另存为字段在子类中。让我举例说明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
}
由于我指的是出现在B的构造函数中的
str
而不是A字段的name
,因此str
将获得默认的private[this] val
修饰符,并将其另存为B
的字段,从而从父类(super class)name
中复制了A
字段。现在,我们有两个重复的字段。关于scala - 如何从Scala的子类中调用父类(super class)构造函数以及如何进行构造函数链接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38160948/