In Kotlin, this, super, and @ labels are used to disambiguate which receiver or superclass member you mean, especially in nested scopes, inheritance, and inner classes.
1. this: refer to the current receiver
Inside a class, this refers to the current instance of that class.
class User(val name: String) {
fun printName() {
println(this.name)
}
}
Usually this is optional:
println(name)
is the same as:
println(this.name)
2. this@Label: choose a specific outer receiver
When you have nested classes, lambdas, or extension functions, there may be multiple possible this receivers. Kotlin lets you qualify this with a label.
Class receiver
class Outer {
val name = "Outer"
inner class Inner {
val name = "Inner"
fun printNames() {
println(this.name) // Inner
println([email protected]) // Inner
println([email protected]) // Outer
}
}
}
this@Outer explicitly means “the this of Outer”.
3. Labels in lambdas
You can label lambdas and then use this@label to access that lambda’s receiver.
class Html {
fun body() {
println("body")
}
}
fun html(block: Html.() -> Unit) {
Html().block()
}
fun main() {
html outer@ {
this.body()
[email protected]()
}
}
Here:
this@outer
refers to the receiver of the lambda labeled outer.
4. super: call superclass implementation
Use super to access a member from the immediate superclass.
open class Parent {
open fun greet() {
println("Hello from Parent")
}
}
class Child : Parent() {
override fun greet() {
super.greet()
println("Hello from Child")
}
}
Output:
Hello from Parent
Hello from Child
5. super<Type>: disambiguate multiple inherited implementations
If a class inherits the same member from multiple supertypes, you must specify which one to call.
interface A {
fun greet() {
println("Hello from A")
}
}
interface B {
fun greet() {
println("Hello from B")
}
}
class C : A, B {
override fun greet() {
super<A>.greet()
super<B>.greet()
println("Hello from C")
}
}
Here:
super<A>.greet()
super<B>.greet()
select the specific supertype implementation.
6. super@Label: access an outer class’s superclass
In inner classes, super normally refers to the superclass of the inner class. If you need the superclass of an outer class, use a qualified super.
open class Base {
open fun message() {
println("Base")
}
}
open class OuterBase : Base() {
override fun message() {
println("OuterBase")
}
}
class Outer : OuterBase() {
override fun message() {
println("Outer")
}
inner class Inner {
fun callOuterSuper() {
[email protected]()
}
}
}
Here:
[email protected]()
means “call the superclass implementation of Outer”.
So this calls:
OuterBase.message()
not Outer.message().
7. Combining super<Type>@Label
If the outer class implements multiple supertypes, you can combine both forms.
interface A {
fun print() {
println("A")
}
}
interface B {
fun print() {
println("B")
}
}
class Outer : A, B {
override fun print() {
println("Outer")
}
inner class Inner {
fun callOuterSupers() {
super<A>@Outer.print()
super<B>@Outer.print()
}
}
}
Here:
super<A>@Outer.print()
super<B>@Outer.print()
means:
- call
A’s implementation as inherited byOuter - call
B’s implementation as inherited byOuter
Summary
| Syntax | Meaning |
|---|---|
this |
Current receiver |
this@Outer |
this of a specific labeled or outer receiver |
super |
Immediate superclass implementation |
super<Type> |
Specific superclass or interface implementation |
super@Outer |
Superclass implementation of an outer class |
super<Type>@Outer |
Specific supertype implementation of an outer class |
In short:
this@Something
chooses which object/receiver you mean.
super<Something>
chooses which superclass/interface implementation you mean.
super<Something>@Outer
chooses which supertype implementation of which outer receiver you mean.
