The only thing we learnt about this
pointer in other languages is “this is an implicit pointer which points to the calling object”. As clear from the definition, it points to the object which calls the respective function or property.
Now the real problem arises when we have an inner class or anonymous interface implementation. We lose the reference of the outer class. Let me give you an example.
//java code
//extending Android View class
public class CustomView extends View {
public CustomView(Context context) {
super(context);
getViewTreeObserver()
.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout() {
//this.
//will not get the reference of
//CustomView here
}
});
}
}
In the above code, we extended the class from View
class which has a property of class ViewTreeObserver
. ViewTreeObserver
class has two functions addOnGlobalLayoutListener
and removeGlobalOnLayoutListener
which takes OnGlobalLayoutListener
Interface reference object.
Now when we implemented the anonymous object of OnGlobalLayoutListener
for the same, we can’t get the reference of my CustomView
class inside the overridden method. Now If we want to call any function of CustomView
from inside the overridden method, we can’t.
To do the same we need to define another final variable and use it.
//java code
//extending Android View class
public class CustomView extends View {
public CustomView(Context context) {
super(context);
final CustomView view = this;
getViewTreeObserver()
.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout() {
view.doSomething();
}
});
}
private void doSomething(){
}
}
Now to make our life easy, Kotlin has something called qualified ‘this’.
Let me give you the equivalent code in Kotlin.
class CustomView : View {
constructor(context: Context) : super(context) {
viewTreeObserver
.addOnGlobalLayoutListener (
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
this@CustomView.doSomething()
}
})
}
private fun doSomething() {
}
}
or if you want to use a lambda
class CustomView : View {
constructor(context: Context) : super(context) {
viewTreeObserver
.addOnGlobalLayoutListener {
this@CustomView.doSomething()
}
}
private fun doSomething() {
}
}
as you can see we can even reference the this
pointer using @
followed by the scope of that this pointer.
Let’s take some other example
class OuterClass {
inner class InnerClass{
fun Int.intExtensionFunction(){
val outerThis = this@OuterClass
val innerThis = this@InnerClass
val intExtThis = this@intExtensionFunction
val currentThis = this
// int receiver, which will be an int
val funLiteral = lambda@ fun String.() {
val funLiteralThis = this
// funLiteral's receiver which will be a string
}
val funLiteral2 = { string: String ->
val funLiteral2This = this
//since this lambada doesn't have any receiver,
//this will be an int (the extension fun reference)
}
}
}
}
We can use any reference inside the inner class or even inner function based on our use case.
Things to remember,
- In a member of a Class,
this
refers to the current object of that class. - In an extension function or a function literal with the receiver,
this
denotes the receiver parameter that is passed on the left-hand side of a dot. - If
this
has no qualifiers, it refers to the innermost enclosing scope. - No need to define any final object to use any
this
reference.