चाइल्ड क्लास के लिए कोटलिन वैरिएबल इनिशियलाइज़ेशन वैल्यू 0 के साथ वैरिएबल इनिशियलाइज़ करने के लिए अजीब व्यवहार करता है


16

मैंने निम्न श्रेणी पदानुक्रम बनाया है:

open class A {
    init {
        f()
    }

    open fun f() {
        println("In A f")
    }
}

class B : A() {
    var x: Int = 33

    init {
        println("x: " + x)
    }

    override fun f() {
        x = 1
        println("x in f: "+ x)
    }

    init {
        println("x2: " + x)
    }
}

fun main() {
    println("Hello World!!")
    val b = B()
    println("in main x : " + b.x)
}

इस कोड का आउटपुट है

Hello World!!
x in f: 1
x: 33
x2: 33
in main x : 33

लेकिन अगर मैं के प्रारंभ बदलने xसे

var x: Int = 33

सेवा

var x: Int = 0

आउटपुट, आउटपुट के विपरीत विधि के मंगलाचरण को दर्शाता है:

Hello World!!
x in f: 1
x: 1
x2: 1
in main x : 1

क्या किसी को पता है कि 0एक दूसरे मूल्य वाले व्यक्ति की तुलना में एक अलग व्यवहार का कारण बनता है?


4
सीधे तौर पर संबंधित नहीं है, लेकिन निर्माणकर्ताओं से अत्यधिक तरीकों को कॉल करना आम तौर पर एक अच्छा अभ्यास नहीं है क्योंकि इससे अप्रत्याशित व्यवहार हो सकता है (और उपवर्गों से सुपरक्लास अनुबंध / आक्रमणकारियों को प्रभावी ढंग से तोड़ना)।
एडम होसेक

जवाबों:


18

सुपर क्लास को सब क्लास से पहले शुरू किया जाता है।

B का कंस्ट्रक्टर कॉल A के कंस्ट्रक्टर को कॉल करता है, जो फंक्शन प्रिंटिंग को "x in f: 1" कहता है, A के इनिशियलाइज़ होने के बाद, B का बाकी हिस्सा इनिशियलाइज़ होता है।

इसलिए अनिवार्य रूप से, मूल्य की स्थापना को अधिलेखित किया जा रहा है।

(जब आप कोटलिन में उनके शून्य मान के साथ प्राइमिटिव्स को इनिशियलाइज़ करते हैं, तो वे तकनीकी रूप से न तो केवल इनिशियलाइज़ करते हैं)

आप हस्ताक्षर को बदलकर इस "ओवरराइट" व्यवहार का पालन कर सकते हैं

var x: Int = 0 सेवा var x: Int? = 0

चूंकि xअब आदिम नहीं है int, इसलिए क्षेत्र वास्तव में मूल्य के लिए आरंभीकृत हो जाता है, जिससे उत्पादन होता है:

Hello World!!
x in f: 1
x: 0
x2: 0
in main x : 0

5
जब आप कोटलिन में उनके शून्य मान के साथ प्राइमिटिव्स को इनिशियलाइज़ करते हैं, तो वे तकनीकी रूप से सिर्फ इनिशियलाइज़ नहीं करते हैं कि मैं क्या पढ़ना चाहता था ... धन्यवाद!
देहरादून

यह अभी भी बग / असंगतता जैसा लगता है।
करुप्पब

2
@ क्रॉपेब यह सिर्फ जावा है, वही व्यवहार अकेले जावा कोड में देखा जा सकता है। इसका
कोटलिन

8

इस व्यवहार का वर्णन प्रलेखन में किया गया है - https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order

यदि उन गुणों में से किसी का उपयोग बेस क्लास आरंभीकरण तर्क में किया जाता है (या तो प्रत्यक्ष या अप्रत्यक्ष रूप से, एक अन्य अप्रचलित खुले सदस्य कार्यान्वयन के माध्यम से), तो यह गलत व्यवहार या एक रनटाइम विफलता हो सकती है। बेस क्लास डिजाइन करते समय, इसलिए आपको कंस्ट्रक्टरों, प्रॉपर्टी इनिशियलाइज़र्स और इनिट ब्लॉक्स में खुले सदस्यों का उपयोग करने से बचना चाहिए।

युपीडी:

एक बग है जो इस असंगति का उत्पादन करता है - https://youtrack.jetbrains.com/issue/KT-15642

जब किसी संपत्ति को सुपर कंस्ट्रक्टर के अंदर वर्चुअल फ़ंक्शन कॉल के साइड-इफ़ेक्ट के रूप में असाइन किया जाता है, तो इसका इनिशलाइज़र प्रॉपर्टी को ओवरराइट नहीं करता है यदि इनिशियलाइज़र एक्सप्रेशन प्रकार का डिफ़ॉल्ट मान (अशक्त, आदिम शून्य) है।


1
इसके अलावा, IntelliJ आपको इसके बारे में चेतावनी देता है। कॉलिंग f()में initके ब्लॉक Aचेतावनी "कॉलिंग निर्माता में गैर अंतिम समारोह च" देता है
Kroppeb

आपके द्वारा प्रदान किए गए प्रलेखन में, यह कहता है कि "बेस क्लास आरंभीकरण पहले चरण के रूप में किया जाता है और इस तरह व्युत्पन्न वर्ग के आरम्भिक तर्क से पहले होता है" जो वास्तव में प्रश्न में पहले उदाहरण में होता है। हालाँकि दूसरे उदाहरण में var x: Int = 0व्युत्पन्न वर्ग का आरम्भिक निर्देश ( ) बिल्कुल भी नहीं चलाया गया है, जो कि प्रलेखन के विपरीत है जो मुझे विश्वास दिलाता है कि यह एक बग हो सकता है।
सुबारू ताशीरो

@SubaruTashiro हां, आप सही कह रहे हैं। यह एक और मुद्दा है - youtrack.jetbrains.com/issue/KT-15642
वणोचेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.