8.2. Klasy i obiekty towarzyszące
Nazwy klas są umieszczane w przestrzeni nazw dotyczącej typów, a nazwy obiektów w przestrzeni nazw dotyczących wartości. Możliwe jest istnienie klasy i obiektu o takich samych nazwach. Obiekt o nazwie takiej, jak klasa, nadaje się do umieszczania w nim metod, których działanie odnosi się w jakiś sposób do instancji klasy, ale nie może być umieszczone w samej klasie. W pliku Objects4.scala znajdują się definicje klasy i obiektu Hello3. Obiekt Hello3 definiuje metodę apply, za pomocą której można tworzyć instancje klasy Hello3.
Plik Objects4.scala: object Hello3 { def apply(greeting: String) = new Hello3(greeting) } class Hello3(greeting: String) { def speak = println(greeting) }
Instancje klasy Hello3 mogą być tworzone zarówno poprzez bezpośrednie wywołanie instrukcji new, jak i pośrednio, poprzez wywołanie metody apply (zarówno jawne jak i niejawne).
scala> val a = new Hello3("hello")
a: Hello3 = Hello3@6374ef
scala> val b = Hello3.apply("hi")
b: Hello3 = Hello3@51f34b
scala> val c = Hello3("hi")
c: Hello3 = Hello3@7eb8cb
scala> a.speak
hello
scala> b.speak
hi
scala> c.speak
hi
Jeśli klasa i obiekt o tych samych nazwach są zdefiniowane w tym samym pliku źródłowym, to w takim przypadku klasę nazywamy klasą towarzyszącą obiektu, a obiekt nazywamy obiektem towarzyszącym klasy. Obiekty towarzyszące mają dostęp do prywatnych składowych klas towarzyszących i odwrotnie.
![]() | Składowe prywatne są oznaczane modyfikatorem private. Informacje na temat ograniczeń dostępu do składowych klas i obiektów, w tym informacje na temat składowych prywatnych, znajdują się w rozdziale 16. |
W pliku Companion1.scala znajdują się definicje obiektu i klasy, które mają takie same nazwy. Obiekt Companion1 jest obiektem towarzyszącym klasy Companion1, a ta klasa jest klasą towarzyszącą tego obiektu.
Plik Companion1.scala: class Companion1(greeting: String) { private def greet1: String = greeting + " (private)" def greet2 = Companion1.greet3 } object Companion1 { def apply(greeting: String) = new Companion1(greeting) private def greet3: String = "Hello (private)" def greet4(instance: Companion1) = instance.greet1 }
Dostęp do prywatnych metod greet1 oraz greet3 z zewnątrz klasy i obiektu jest zabroniony.
scala> val c1 = Companion1("Hi")
c1: Companion1 = Companion1@12ceb35
scala> c1.greet1
<console>:12: error: method greet1 in class Companion1 cannot be accessed in Companion1
c1.greet1
^
scala> Companion1.greet3
<console>:11: error: method greet3 in object Companion1 cannot be accessed in object Companion1
Companion1.greet3
^
Natomiast dostęp do tych metod z obiektu i klasy towarzyszącej — z metod greet2 i greet4 — jest możliwy.
scala> c1.greet2 res5: String = Hello (private) scala> Companion1.greet4(c1) res6: String = Hi (private)
Pliki Companion2a.scala i Companion2b.scala zawierają podobne definicje obiektu i klasy o takich samych nazwach (Companion2), ale tym razem zdefiniowane w osobnych plikach źródłowych. W konsekwencji, obiekt Companion2 nie jest obiektem towarzyszącym klasy Companion2, a klasa Companion2 nie jest klasą towarzyszącą tego obiektu.
Plik Companion2a.scala: class Companion2(greeting: String) { private def greet1 = println(greeting + " (class private)") def greet2 = Companion2.greet3 }
Plik Companion2b.scala: object Companion2 { private def greet3 = println("Hello (object private)") def greet4(instance: Companion2) = instance.greet1 }
Obu plików nie udaje się nawet skompilować — ani osobno, ani razem.
$ scalac Companion2a.scala
Companion2a.scala:3: error: not found: value Companion2
def greet2 = Companion2.greet3
^
one error found
$ scalac Companion2b.scala
Companion2b.scala:3: error: not found: type Companion2
def greet4(instance: Companion2) = instance.greet1
^
one error found
$ scalac Companion2a.scala Companion2b.scala
Companion2b.scala:1: error: Companions 'class Companion2' and 'object Companion2' must be defined in same file:
Found in H:\jps2\examples\Companion2a.scala and H:\jps2\examples\Companion2b.scala
object Companion2 {
^
one error found
Plik Objects4.scala:
object Hello3 {
def apply(greeting: String) = new Hello3(greeting)
}
class Hello3(greeting: String) {
def speak = println(greeting)
}

