From blueprint to object
A class such as Dog is only a blueprint. To get something you can use you create an instance, also called an object. Each instance is a separate value in memory built from the class.
Creating an instance
In Kotlin you call the class name like a function:
val rex = Dog()
There is no new keyword. Writing new Dog() is a compile error (unresolved reference 'new'), because Kotlin reads new as an ordinary name. The call Dog() runs the class's constructor, which builds the object and returns it.
The line does three things:
Dog()creates a freshDogobject.val rexdeclares a variable namedrex. Its type,Dog, is inferred from the right-hand side.- The
=stores a reference to the new object inrex.
The variable holds a reference to the object, not the object itself. With val the reference is fixed: rex = Dog() on a later line fails with 'val' cannot be reassigned. The object it points to can still change, once a class has changeable properties.
Many objects from one class
Each constructor call gives a brand-new, independent object:
val rex = Dog()
val buddy = Dog()
val luna = Dog()
These three variables hold three different objects. They share the blueprint but not their state, so changing one never affects the others.
Same object or equal objects
Two variables can also point to one object. Compare these:
class Dog
fun main() {
val rex = Dog()
val buddy = Dog()
val same = rex
println(rex === buddy)
println(rex == buddy)
println(rex === same)
}
The output is:
false
false
true
=== asks whether two references point to the very same object. == asks whether the objects are equal, which for a plain class with no equals of its own means the same thing as ===. So rex and buddy, made by separate calls, are different, while same is just a second name for rex.
Where the object lives
Objects of a class are created while the program runs, usually inside a function. A variable declared inside mainFunction is local: it exists while that function runs and is not visible outside it. When no variable refers to an object any longer, the JVM's garbage collector reclaims its memory on its own, so Kotlin code never frees objects by hand.
A constructor call is an expression, so you do not have to store the result. Dog() on its own line creates a dog and immediately forgets it. Storing it in a val is what lets you use it afterwards.
The exercise
The Dog class already exists. The starter code in mainFunction has three checks that print a line for every variable that holds an object:
if (rex != null) println("rex exists")
if (buddy != null) println("buddy exists")
if (luna != null) println("luna exists")
Those names do not exist yet, so the code does not compile. The steps declare them, one per line, each with its own constructor call:
class Dog {
}
class Solution {
fun mainFunction() {
val rex = Dog()
val buddy = Dog()
val luna = Dog()
if (rex != null) println("rex exists")
if (buddy != null) println("buddy exists")
if (luna != null) println("luna exists")
}
}
Running it prints rex exists, buddy exists and luna exists. The compiler adds a warning that each condition is always true. That is correct: a Dog variable can never be null. In Kotlin a type without a question mark never holds null, so these checks only exist to make the lesson print something.
Common mistakes
- Using
new. It is valid in some other languages but not in Kotlin. - Leaving out the parentheses.
val rex = Dogdoes not create an object. OnlyDog()calls the constructor. - Reusing one variable for all three dogs. The lesson needs three variables,
rex,buddyandluna, each with its own object. - Typing
Dog rex = Dog(). Kotlin puts the name first:val rex: Dog = Dog(), and the: Dogis usually omitted.
Key takeaways
- Create an object by calling the class name:
Dog(). There is nonew. - Every call creates a separate object.
- A variable holds a reference;
===checks whether two references point to the same object. - A non-nullable type such as
Dogcan never benull.