简体   繁体   English

抽象类与其具体类之间的Kotlin类参数值

[英]Kotlin class parameter value between abstract class and its concrete class

I have a problem understanding how class parameter value behaves between abstract/concrete classes. 我在理解类参数值在抽象/具体类之间的行为方式时遇到问题。

Abstract class example: 抽象类示例:

abstract class A {

   init {
       initStuff()
   }

   fun initStuff() {
       additionalInit()
   }

   abstract fun additionalInit()
}

Concrete class example: 具体的类示例:

class B(val exParam: Int): A {

    init {
       println("$exParam") // This would give expected value.
    }

    override fun additionalInit() {
       println("$exParam") // Always zero even if exParam value is set.
    }
}

My question is that based on my understanding, I want to call B(1000) and expect both println inside the B class to print 1000 but this was not the case so my understanding is clearly off here so anyone can light me to the right understanding? 我的问题是,根据我的理解,我想调用B(1000)并期望B类中的两个println都可以打印1000但事实并非如此,因此我的理解很明显,因此任何人都可以将我理解为正确的理解?

Note what you are using here is an anti-pattern, ie calling a method from the constructor which is overridable by subclasses and that for the very reason you now realise as an unexpected behaviour. 注意,这里使用的是反模式,即从构造函数中调用一个可以被子类覆盖的方法,由于这个原因,您现在意识到这是一种意外行为。

Now what's happening here: before you can even initialize B A needs to be constructed first. 现在,这里发生了什么:在甚至可以初始化B之前,首先需要构造A So the constructors and init of A get called first. 因此,首先调用A的构造函数和init But the variable for B is not assigned yet at that very moment. 但是那时B的变量尚未分配。 So that's why we still have that 0 there. 这就是为什么我们那里仍然有0 Even if you set a default value of, lets say -1 (ie val exParam : Int = -1 ), you will see rather 0 here as output. 即使您将默认值设置为-1 (即val exParam : Int = -1 ),您在此处也会看到0

Summarizing: never ever call overridable functions in a constructor or init... Read more about it here: What's wrong with overridable method calls in constructors? 总结:永远不要在构造函数或init中调用可重写函数...在此了解更多信息:构造函数中的可重写方法调用有什么问题?

inheritance here works just like in Java. 这里的继承就像在Java中一样工作。 If you were to translate your construct into Java code, it would look something like this: 如果要将构造转换为Java代码,它将看起来像这样:

abstract class A {

    public A() {
        additionalInit();
    }

    abstract void additionalInit();

}

class B extends A {

    private int exParam;

    public B(int exParam) {
        // You can see here that this.exParam is initialized AFTER you're calling the super constructor
        super();
        this.exParam = exParam;
    }

    // getters and setters

}

Your IDE should give you a warning if you are trying to call abstract function from the init block because of this. 因此,如果您试图从init块调用抽象函数,您的IDE应该给您警告。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM