Use of the object keyword in Kotlin.
fun main() {
println(CompanyCommunications.getTagLine()) // Call the class name as there is only one instance
println(CompanyCommunications.getCopyRightLine())
SomeOtherClass().printPrivateVar() // Will allow us access to privateVar despite being private, thanks to Companion object
SomeClass2.SomeCompanion.accessPrivateVar() // Using companion name, but again redundant
val someClass = SomeClass4.justAssign("this is the string as is")
val someClass2 = SomeClass4.upperOrLowerCase("this is the string as is", false)
println(someClass.someString)
println(someClass2.someString)
// val someClass3 = SomeClass4("This will not work") // Constructor is private so cannot instantiate directly
var thisIsMutable = 45
wantsSomeInterface(object: SomeInterface { // Uses object to create an instance of the someInterface interface - NOT a Singleton. Is generated and then destroyed. Can use multiple interfaces, unlike Java
override fun mustImplement(num: Int): String {
return "This is from mustImplement: ${num * 100 + thisIsMutable}" // This expression can access variables from outside it (val or var, doesn't need to be final), unlike Java
}
})
}
// 'object' keyword's 3 uses: Singletons, companion objects, object expressions
// Singletons
// //In Java, you would create a private constructor that allows only one instance which other classes can access
// In Kotlin, there can only be one instance of an 'object' class, so we use that:
object CompanyCommunications { // No class keyword needed. Also no constructors as instance is created instantaneously
val currentYear = Year.now().value
fun getTagLine() = "Our company rocks!"
fun getCopyRightLine() = "Copyright \u00A9 $currentYear Our Company. All rights reserved."
}
// Companion Objects
// No static keyword in Kotlin - instead we can use top-level functions and properties, and Object declarations (above)
// But what if you want an equivalent to Java static (see Java objects below), where you can access functions and properties without creating an instance of the class?
// We create companion objects inside the class which can be accessed without having to generate an instance of the class
class SomeClass {
companion object {
private var privateVar = 6 // Because is private no getter/setter generated
fun accessPrivateVar() {
println("I'm accessing privateVar: $privateVar")
}
}
}
class SomeClass2 {
companion object SomeCompanion { // You can also name your companion object, but little use
private var privateVar = 6
fun accessPrivateVar() {
println("I'm accessing privateVar: $privateVar")
}
}
}
class SomeOtherClass() {
fun printPrivateVar () {
println(SomeClass.accessPrivateVar()) // Could use SomeClass.Companion.accessPrivateVar() but redundant
}
}
class SomeClass3 {
val someString: String
constructor(str: String) { // First secondary constructor
someString = str
}
constructor(str: String, lowerCase: Boolean) { // Second secondary constructor
if (lowerCase) {
someString = str.toLowerCase()
} else {
someString = str.toUpperCase()
}
}
// But instead of doing it this way we can create a companion class that returns an instance of the class (see below)
}
class SomeClass4 private constructor(val someString: String){ // We want to implement the Factory pattern here. This class should generate instances of the class - nobody should be able to do it directly as in SomeClass3, so primary is made private
companion object{
private var privateVar = 6
fun accessPrivateVar() {
println("I'm accessing privateVar in SomeClass4: $privateVar")
}
fun justAssign(str: String) = SomeClass4(str) // Can only call the private constructor from inside class therefore controlling how class is instantiated...
fun upperOrLowerCase(str: String, lowerCase: Boolean): SomeClass4 { // so to get an instance of this class you have to go through either the justAssign or upperOrLowerCase function
if (lowerCase) {
return SomeClass4(str.toLowerCase())
} else {
return SomeClass4(str.toUpperCase())
}
}
}
}
// Object expressions - equivalent to an anonymous object in Java
interface SomeInterface {
fun mustImplement(num: Int): String
}
fun wantsSomeInterface(si: SomeInterface) {
println("Printing from wantsSomeInterface - ${si.mustImplement(22)}")
}
Companion object equivalent in Java
public class SomeClass {
private static int privateVar = 6;
public static void main(String[] args) {
new SomeOtherClass().someOtherMethod();
}
public static void accessPrivateVar() {
System.out.println("I'm accessing privateVar: " + privateVar);
}
}
public class SomeOtherClass {
public void someOtherMethod() {
SomeClass.accessPrivateVar();
}
}
