I am sure, most Android/Java developers are already aware of this concept that when an anonymous class is defined within the body of a method, only variables declared final in the scope of that method are accessible from within the inner class. If you want to read more about it, I have attached some references at the bottom of this article. Let’s continue for now.
Just to refresh your memory, look at the following Java examples:
Most of us would have seen this error and would have easily fixed it.
The above compilation error message is good enough to help us fix this error. We are trying to access a non-final variable methodLocalVariable from the anonymous class, and changing this variable to final will fix this compilation error like shown in the following code:
At this point, some of you may say that with Java 8 and lambda in the picture you don’t have to use the final keyword, and you are right.
The following snippet is using Java 8 lambda and there is no need to use the final keyword.
We don’t see any error here even though the final keyword is not used here, It is because the methodLocalVariable in the above code is implicitly final or so-called effectively final.
Java 8 has introduced a new concept called "effectively final" variable. A non-final local variable or method parameter whose value is never changed after initialisation is known as effectively final.
This means in our case, we can use methodLocalVariable inside the anonymous class without making use of the final keyword but it can still not be changed.
See what happens when we try to change the value of methodLocalVariable
We get a compilation error as the variable used in lambda expression should be final or effectively final.
Have you ever noticed the same behaviour while programming in Kotlin? Let me help you recall it.
The above code mimics what we have seen in our Java example and as you can see there is no compilation error while using methodLocalVariable inside the anonymous class, and yeah it is pretty obvious as we are using val methodLocalVariable, val is similar to final in java.
But, what if we try to use var methodLocalVariable instead of val methodLocalVariable ?
Would it work? Would it give an error? Let’s find out !!!
Not only can we use methodLocalVariable2 inside an anonymous class but also modify it and no error at all.
How is it possible in Kotlin when the same seems to be not allowed in Java? Let me answer that.
Whenever a var type variable from the enclosing method is used inside an anonymous class and some changes are made to that variable’s value,
this var variable is considered as an IntRef or ObjectRef based on the type of variable.
In our case, var methodLocalVariable2 will be treated as methodLocalVariable2 of type IntRef.
An ObjectRef or IntRef is a Serializable class that has one variable name element of type T.
Whatever value that we store in methodLocalVariable2 gets stored in the element variable and whenever we make some changes to methodLocalVariable2’s value, in actuality, those changes are being performed at the element variable.
Hence we are making changes to the methodLocalVariable2.element, not to the methodLocalVariable2.
Let me show you how the decompiled code looks like for the “Anonymous class with var” example that we saw above.
It is pretty clear from the above screenshot, how our var are mapped to Ref classes.
var methodLocalVariable2 →→→→→→→→→IntRef methodLocalVariable2
var stringVar →→→→→→→→→→→→→→→ObjectRef stringVar
I hope by now we have understood how var behaves in an anonymous class and how making changes to var is allowed in an anonymous class in Kotlin.
Let me know in the comments if you have any doubts or suggestions.