# Creating Classes
Not only can you use predefined types like
IntRange
andString
, you can also create your own types of objects.
Indeed, creating new types comprises much of the activity in object-oriented programming. You create new types by defining classes.
An object is a piece of the solution for a problem you’re trying to solve. Start by thinking of objects as expressing concepts. As a first approximation, if you discover a “thing” in your problem, represent that thing as an object in your solution.
Suppose you want to create a program to manage animals in a zoo. It makes sense to categorize the different types of animals based on how they behave, their needs, animals they get along with and those they fight with. Everything different about a species of animal is captured in the classification of that animal’s object. Kotlin uses the class
keyword to create a new type of object:
// CreatingClasses/Animals.kt
// Create some classes:
class Giraffe
class Bear
class Hippo
fun main() {
// Create some objects:
val g1 = Giraffe()
val g2 = Giraffe()
val b = Bear()
val h = Hippo()
// Each object() is unique:
println(g1)
println(g2)
println(h)
println(b)
}
/* Sample output:
Giraffe@28d93b30
Giraffe@1b6d3586
Hippo@4554617c
Bear@74a14482
*/
To define a class, start with the class
keyword, followed by an identifier for your new class. The class name must begin with a letter (A-Z, upper or lower case), but can include things like numbers and underscores. Following convention, we capitalize the first letter of a class name, and lowercase the first letter of all val
s and var
s.
Animals.kt
starts by defining three new classes, then creates four objects (also called instances) of those classes.
Giraffe
is a class, but a particular five-year-old male giraffe that lives in Botswana is an object. Each object is different from all others, so we give them names like g1
and g2
.
Notice the rather cryptic output of the last four lines. The part before the @
is the class name, and the number after the @
is the address where the object is located in your computer’s memory. Yes, that’s a number even though it includes some letters—it’s called “hexadecimal notation” (opens new window). Every object in your program has its own unique address.
The classes defined here (Giraffe
, Bear
, and Hippo
) are as simple as possible: the entire class definition is a single line. More complex classes use curly braces ({
and }
) to create a class body containing the characteristics and behaviors for that class.
A function defined within a class belongs to that class. In Kotlin, we call these member functions of the class. Some object-oriented languages like Java choose to call them methods, a term that came from early object-oriented languages like Smalltalk. To emphasize the functional nature of Kotlin, the designers chose to drop the term method, as some beginners found the distinction confusing. Instead, the term function is used throughout the language.
If it is unambiguous, we will just say “function.” If we must make the distinction:
- Member functions belong to a class.
- Top-level functions exist by themselves and are not part of a class.
Here, bark()
belongs to the Dog
class:
// CreatingClasses/Dog.kt
class Dog {
fun bark() = "yip!"
}
fun main() {
val dog = Dog()
}
In main()
, we create a Dog
object and assign it to val dog
. Kotlin emits a warning because we never use dog
.
Member functions are called (invoked) with the object name, followed by a .
(dot/period), followed by the function name and parameter list. Here we call the meow()
function and display the result:
// CreatingClasses/Cat.kt
class Cat {
fun meow() = "mrrrow!"
}
fun main() {
val cat = Cat()
// Call 'meow()' for 'cat':
val m1 = cat.meow()
println(m1)
}
/* Output:
mrrrow!
*/
A member function acts on a particular instance of a class. When you call meow()
, you must call it with an object. During the call, meow()
can access other members of that object.
When calling a member function, Kotlin keeps track of the object of interest by silently passing a reference to that object. That reference is available inside the member function by using the keyword this
.
Member functions have special access to other elements within a class, simply by naming those elements. You can also explicitly qualify access to those elements using this
. Here, exercise()
calls speak()
with and without qualification:
// CreatingClasses/Hamster.kt
class Hamster {
fun speak() = "Squeak! "
fun exercise() =
this.speak() + // Qualified with 'this'
speak() + // Without 'this'
"Running on wheel"
}
fun main() {
val hamster = Hamster()
println(hamster.exercise())
}
/* Output:
Squeak! Squeak! Running on wheel
*/
In exercise()
, we call speak()
first with an explicit this
and then omit the qualification.
Sometimes you’ll see code containing an unnecessary explicit this
. That kind of code often comes from programmers who know a different language where this
is either required, or part of its style. Using a feature unnecessarily is confusing for the reader, who spends time trying to figure out why you’re doing it. We recommend avoiding the unnecessary use of this
.
Outside the class, you must say hamster.exercise()
and hamster.speak()
.
Exercises and solutions can be found at www.AtomicKotlin.com.