Lists Review and Performance : 03/31/2023
Linked Lists : 03/30/2023
Algorithms and Lists : 03/29/2023
Lambda Expressions : 03/24/2023
Anonymous Classes : 03/23/2023
Practice with Interfaces : 03/22/2023
Implementing Interfaces : 03/21/2023
Using Interfaces : 03/20/2023
Working with Exceptions : 03/10/2023
Throwing Exceptions : 03/09/2023
Catching Exceptions : 03/08/2023
References and Polymorphism : 03/07/2023
References : 03/06/2023
Data Modeling 2 : 03/03/2023
Equality and Object Copying : 03/02/2023
Polymorphism : 03/01/2023
Inheritance : 02/28/2023
Data Modeling 1 : 02/27/2023
Companion Objects : 02/24/2023
Encapsulation : 02/23/2023
Constructors : 02/22/2023
Objects, Continued : 02/21/2023
Introduction to Objects : 02/20/2023
Compilation and Immutability : 02/17/2023
Practice with Collections : 02/16/2023
Maps and Sets : 02/15/2023
Lists and Type Parameters : 02/14/2023
Imports and Libraries : 02/13/2023
Multidimensional Arrays : 02/10/2023
Practice with Strings : 02/09/2023
null : 02/08/2023
Algorithms and Strings : 02/07/2023
Strings : 02/06/2023
Functions and Algorithms : 02/03/2023
Practice with Functions : 02/02/2023
More About Functions : 02/01/2023
Errors and Debugging : 01/31/2023
Functions : 01/30/2023
Practice with Loops and Algorithms : 01/27/2023
Algorithms : 01/26/2023
Loops : 01/25/2023
Arrays : 01/24/2023
Compound Conditionals : 01/23/2023
Conditional Expressions and Statements : 01/20/2023
Operations on Variables : 01/19/2023
Variables and Types : 01/18/2023
Welcome to CS 124 : 01/17/2023
Companion Objects
class Math {
companion object {
const val PI = 3.141597
fun pow(base: Int, exponent: Int): Int {
assert(exponent >= 0) { "No support for negative exponents" }
var result = 1
for (i in 0 until exponent) {
result *= base
}
return result
}
}
}
println(Math.PI)
println(Math.pow(2, 3))
As we continue, we begin by describing a feature of Kotlin objects called companion
objects.
We’ll also introduce introduce one new piece of object syntax.
But first, let’s warm up with another graded debugging challenge!
this
is a keyword in Kotlin that you can use in your instance methods.
It always refers to the current instance that is executing the method.
So this:
class Course(var number: String) {
fun changeNumber(newNumber: String) {
number = newNumber
}
}
is equivalent to this:
class Course(var number: String) {
fun changeNumber(newNumber: String) {
this.number = newNumber
}
}
The example above is one use of this
.
However, we’ll usually just go the first route, and choose parameter names that don’t conflict with our instance variable names.
This helps avoid mistakes.
However, there is one place where we do and will use this
.
Let’s go through it together:
class Course(var number: String)
Up until now the properties and methods that we’ve been establishing on our Kotlin objects are instance properties and methods.
Meaning each instance of an class has its own:
class Person(val name: String) {
fun doubleName(): String {
return name + name
}
}
val first = Person("Geoff")
val second = Person("Chuchu")
println(first.name)
println(second.name)
println(first.doubleName())
Even though they share an implementation of doubleName
, instances each act like they have their own doubleName
method.
However, Kotlin also allows us to create methods that are provided by the class and can be accessed without an instance.
We do this using something called a companion object.
Let’s see how:
class Person(val name: String)
Companion object methods cannot access instance variables.
Let’s look at why, and the differences between class and instance methods:
class Person(val name: String) {
companion object {
fun getName(): String {
return name
}
}
}
val student = Person("You")
println(student.getName())
In Kotlin, we can create methods that are not associated with any class, simply by declaring them outside a class body:
class Person(val name: String)
fun greetPerson(person: Person) {
println("Hello ${person.name}!")
}
val geoff = Person("Geoff")
greetPerson(geoff)
This works completely fine, and limits the degree to which we need to use companion objects.
So if you have a method that doesn’t need an instance, you can either declare it outside the class or in a companion object.
Companion objects can also declare fields, just like instances:
class Person(val name: String) {
companion object {
val typicalGreeting = "Hello"
}
}
println(Person.typicalGreeting)
This can be a good place to put constant values, as shown above, particularly if, like a method, they really belong with the class
that defines the companion object.
You can also define non-constant (i.e., var
) properties on companion objects.
However.
This is extremely rare, and very easy to get wrong.
So much so that we won’t bother demonstrating how to do it!
More Practice
Need more practice? Head over to the practice page.