Reputation: 672
Faced with unexpected problem. Here is simple class:
class PaymentPrintTest {
init {
prepareToPrint()
}
private var sale: Int? = null
private var saleContent: ArrayList<Int> = ArrayList()
private fun prepareToPrint() {
sale = 5
saleContent = arrayListOf(1,2,3)
Log.i("WhereIsContent?", "prepare sale: $sale")
Log.i("WhereIsContent?", "prepare saleContent: ${saleContent.size}")
}
fun startPrint() {
Log.i("WhereIsContent?", "start sale: $sale")
Log.i("WhereIsContent?", "start saleContent: ${saleContent.size}")
}
}
This way I call method startPrint:
PaymentPrintTest().startPrint()
In logcat I see:
I/WhereIsContent?: prepare sale: 5
I/WhereIsContent?: prepare saleContent: 3
I/WhereIsContent?: start sale: 5
I/WhereIsContent?: start saleContent: 0
The question is where the content of saleContent value has gone? And why 'sale' variable has correct value at the same time?
Upvotes: 0
Views: 118
Reputation: 8899
I know the answers above provide correct result. But, I just want to give a bit of an explanation.
1) lets start with
var sale: Int? = null
if init block comes before declaration of properties, init block just takes its property names not values assigned to them(even if it were var sale: Int? = 4, it would ignore 4). It assigns default values to them, in your case null, but this null is NOT the one you assigned, it is default null of nullable property. So if it was var sale: Int = 4, value of sale in init block would be 0(default value of Int). Then, you assigned 5 to sale. After init block finishes, sale property is checked. If default value has been assigned to that property(in your case null) it just ignores the assigment(leaving with its current value which is 5), otherwise it reassigns the property again(so if it were var sale: Int? = 4, it would again reassign it to 4)
But, if init comes after property declaration, everything should be clear and as expected;).
2) lets turn to
private var saleContent: ArrayList = ArrayList()
in this case, saleContent's property name is taken(not ArrayList()) and because no default value for this, nothing is assigned to it. Inside init block you assigned (1, 2, 3) which changed its value from not assigned to (1,2,3). But, when init block finished, it was reassigned to (ArrayList()) because ArrayList() is not default value of ArrayList.
but if put properties above init, it works as usual.
private var sale1: Int? = null
private var sale2: Int? = 3
private var sale3: Int = 0
private var sale4: Int = 9
private var saleContent: ArrayList<Int>? = null
lateinit var saleContent2: ArrayList<Int>
if you play around with these values, I hope you will have more understanding.
But generally, I would suggest putting init block after property declaration to be safe.
Upvotes: 0
Reputation: 18568
You can make saleContent
a lateinit var
, but you have to remove the direct initialization for that. See this example:
class PaymentPrintTest {
init {
prepareToPrint()
}
private var sale: Int? = null
private lateinit var saleContent: ArrayList<Int>
private fun prepareToPrint() {
this.sale = 5
this.saleContent = arrayListOf(1,2,3)
println("WhereIsContent?\tprepare sale: $sale")
println("WhereIsContent?\tprepare saleContent: ${saleContent.size}")
}
fun startPrint() {
println("WhereIsContent?\tstart sale: $sale")
println("WhereIsContent?\tstart saleContent: ${saleContent.size}")
}
}
I had to use println()
instead of Log
because I wrote this in the Kotlin Playground without a LogCat...
However, the result of
fun main() {
PaymentPrintTest().startPrint()
}
is
WhereIsContent? prepare sale: 5
WhereIsContent? prepare saleContent: 3
WhereIsContent? start sale: 5
WhereIsContent? start saleContent: 3
It obviously works this way, but it also does the way @Jaime answered.
Upvotes: 0
Reputation: 6981
As you initialise arraylist globally it will take global arraylist for both method.
If you change it like this it will work as you want.
class PaymentPrintTest {
init {
prepareToPrint()
}
private var sale: Int? = null
private var saleContent: ArrayList<Int>? = null
private fun prepareToPrint() {
sale = 5
saleContent = arrayListOf(1,2,3)
Log.i("WhereIsContent?", "prepare sale: $sale")
Log.i("WhereIsContent?", "prepare saleContent: ${saleContent?.size}")
}
fun startPrint() {
Log.i("WhereIsContent?", "start sale: $sale")
Log.i("WhereIsContent?", "start saleContent: ${saleContent?.size}")
}
}
output :
> I/WhereIsContent?: prepare sale: 5
I/WhereIsContent?: prepare saleContent: 3
I/WhereIsContent?: start sale: 5
I/WhereIsContent?: start saleContent: 3
Upvotes: 0
Reputation: 388
Move sale and saleContent above init, properties should be at the very top
Upvotes: 3