Inheritance 正在转换Kotlin中父构造函数的子构造函数参数
我是一名Java老手,正在学习Kotlin。我发现自己对如何获取提供给子类的构造函数参数并将其转换为父类所需的参数感到有点困惑。当提供给子对象的参数不适用于父对象时,就会出现问题 例如,当我有IntelliJ IDEA时,将以下内容转换为KotlinInheritance 正在转换Kotlin中父构造函数的子构造函数参数,inheritance,kotlin,constructor,Inheritance,Kotlin,Constructor,我是一名Java老手,正在学习Kotlin。我发现自己对如何获取提供给子类的构造函数参数并将其转换为父类所需的参数感到有点困惑。当提供给子对象的参数不适用于父对象时,就会出现问题 例如,当我有IntelliJ IDEA时,将以下内容转换为Kotlin class Base { final int w; final int h; Base(int w, int h) { this.w = w; this.h = h; } }
class Base
{
final int w;
final int h;
Base(int w, int h)
{
this.w = w;
this.h = h;
}
}
class Derived extends Base
{
Derived(int x)
{
// some complex derivation
Converter c = new Converter(x);
super(c.a, c.b);
}
}
class Converter
{
final int a;
final int b;
Converter(int x)
{
a = x + 2;
b = x - 2;
}
}
我得到以下信息,包括指示位置处的一个错误,表示未为w
和h
传递参数
open class Base(val w: Int, val h: Int)
class Derived(x: Int) : Base() {
// ^ error
init {
// some complex derivation
val c = Converter(x)
// How do I provide c.a and c.b?
}
}
class Converter(x: Int) {
val a: Int
val b: Int
init {
a = x + 2
b = x - 2
}
}
这个问题的一般解决办法是什么?(很明显,我并没有做这里所示的简单的事情。我简化只是为了说明问题。)上面JB Nizet的评论让我走上了正确的轨道:在Java中也不能这样做。我一直在绞尽脑汁,试图用科特林的方式做事。在本例中,我尝试在Java中使用访问器方法的任何地方使用属性 一种解决方案是将基本属性抽象化:
abstract class Base {
abstract val w: Int
abstract val h: Int
// base implementation
}
class Derived(x: Int) : Base() {
private val c = Converter(x)
override val w: Int
get() = c.a
override val h: Int
get() = c.b
}
class Converter(x: Int) {
// implementation not relevant here
val a = x + 2
val b = x - 2
}
我建议使用更简单的私有构造函数,并添加工厂方法来进行转换,例如:
class Derived private constructor(val w: Int, val h: Int) : Base(w, h) {
companion object {
operator fun invoke(x: Int): Derived {
// Some complex derivation…
val c = Converter(x)
return Derived(c.a, c.b)
}
}
}
这可以用与构造函数完全相同的方式调用,例如val d=Derived(1)
,但它有几个优点:
- 它可以在调用构造函数之前进行大量处理
- 在适当的情况下,它可以返回缓存值而不是新实例
- 它可以返回一个子类。(因此,
可以是一个抽象类,或者您可能根本不需要它。)确切的类可以在调用之间有所不同,甚至可以是匿名类型派生的
- 它可以有一个名称。如果需要使用相同参数的多个方法(例如,可以由矩形坐标或极坐标构造的点对象),这一点尤为重要。但是,工厂方法不需要特定名称;如果在伴生对象中实现
方法(如上所述),则可以使用与构造函数完全相同的方式调用它invoke()
- 这样可以更容易地更改类的实现,而不会影响其公共接口
- 子类构造函数不能使用它
转换器
对象;这完全是调用构造函数的另一种方式
(在某些情况下,您可能不需要将主构造函数设置为私有;它可以提供工厂方法的替代方法,只要签名不匹配。)Java代码无效。super()必须是子构造函数的第一条指令。因此,Java中的问题与Kotlin中的问题完全相同,不是吗?啊!你是对的!我正试图用Kotlin的方式来做事情——在本例中,使用属性而不是访问器方法。也许我的解决方案是在基类中使用抽象属性。调查…哦,对了,一个带有私有构造函数的工厂方法也可以完成这项工作。您的意思是通过
Derived(1)
构造—只有一个参数吗?我非常喜欢Kotlin,但在这种情况下,Java提供了更容易理解的语法,即使更长。我不知道这种创建虚拟二级构造函数的方法。谢谢你的提示@乔拉普:是的,那是一个打字错误——现在已经修好了!伴随对象非常常见,因此您已经习惯了语法;这大致相当于Java中的静态方法。您在这里演示了Kotlin可以做我想做的事情,即使Java做不到。在Java中,它将是一个静态方法调用派生的.create(1)
。我对解决方案中的所有概念都感到有点奇怪,但科特林给我留下了更深刻的印象。再次感谢!