Companion objects are a special type of object in Scala that are defined in the same source file as a class and have the same name as the class. Companion objects have several interesting features that make them useful in many contexts. Here’s an overview of companion objects in Scala:
1. Accessing private members: Companion objects can access the private members of their corresponding class. This allows you to define static methods and constants for a class, while still keeping the implementation details of those methods and constants hidden from other classes. Here’s an example:
“
class Person(name: String, age: Int)
object Person {
private val defaultName = “John”
private val defaultAge = 30
def create(): Person = new Person(defaultName, defaultAge)
}
val person = Person.create()
In this example, “Person” is a class that has two fields (“name” and “age”). The companion object “Person” has two private fields (“defaultName” and “defaultAge”) and a method (“create”) that creates a new instance of the class with the default values. Because the companion object is defined in the same source file as the class, it can access the private fields of the class.
2. Factory methods: Companion objects can also be used to define factory methods for a class. A factory method is a method that creates instances of a class, rather than using the constructor directly. Here’san example:
`
class Person(name: String, age: Int)
object Person {
def create(name: String, age: Int): Person = new Person(name, age)
}
val person = Person.create(“John”, 30)
`
In this example, “Person” is a class that has two fields (“name” and “age”). The companion object “Person” has a method “create” that creates a new instance of the class with the specified values. This allows you to create instances of the class without using the constructor directly, which can be useful in some contexts.
3. Sharing behavior: Companion objects can also be used to share behavior across multiple classes. If two or more classes have similar behavior, you can define that behavior in a companion object and then mix it in with each of the classes. Here’s an example:
`
trait Greeting {
def sayHello(name: String): Unit = {
println(s”Hello, $name!”)
}
}
class Person(name: String) extends Greeting
object Person extends Greeting {
def apply(name: String): Person = new Person(name)
}
val person = Person(“John”)
person.sayHello(“Mary”) // prints “Hello, Mary!”
`
In this example, “Person” is a class that takes a single parameter (“name”) and extends the “Greeting” trait, which defines a “sayHello” method. The companion object “Person” also extends the “Greeting” trait and provides a factory method (“apply”) that creates a new instance of the class with the specified name. By mixing in the “Greeting” trait with both the class and the companion object, we can share the “sayHello” method across both.
Overall, companion objects in Scala are a powerful feature that allows you to define static methods and constants, factory methods, and shared behavior for a class. By defining a companion object in the same source file as a class, you can access the private members of the class and share behavior across multiple classes.