16.6. Kwalifikowany dostęp chroniony

Pozostała do pokazania trzecia, kwalifikowana postać modyfikatora protected. Metoda speak z klasy Greeting, zdefiniowana w pliku QualifiedProtedted1.scala, jest poprzedzona modyfikatorem private[hello]. To oznacza, że powinna być dostępna w całym pakiecie hello.

Plik QualifiedProtected1.scala:
package hello {
  class Greeting(greeting: String) {
    private[hello] def speak = println(greeting)
  }
  object Hello {
    def speak = new Greeting("Hello!!!!").speak
  }
}

W pakiecie hello znajduje się jedno odwołanie do tej metody — w definicji obiektu Hello. Ponieważ znajduje się w pakiecie hello, to kompilator kompiluje ten kod bez błędów.

$ scalac QualifiedProtected1.scala

$

W pliku QualifiedProtected2.scala znajduje się próba zdefiniowania obiektu Hi, dziedziczącego z klasy Greeting.

Plik QualifiedProtected2.scala:
object Hi extends hello.Greeting("Hi!!!!") {
  def hi = speak
}

Obiekt Hi nie kompiluje się, gdyż próbuje uzyskać dostęp do metody speak spoza pakietu hello, co jest niemożliwe.

$ scalac QualifiedProtected1.scala QualifiedProtected2.scala
QualifiedProtected2.scala:2: error: method speak in class Greeting cannot be accessed in object Hi
  def hi = speak
           ^
one error found

Potrzebna jest zmiana kwalifikatora private[hello] na protected[hello] w definicji metody speak. Poprawiona definicja znajduje się w pliku QualifiedProtected3.scala.

Plik QualifiedProtected3.scala:
package hello {
  class Greeting(greeting: String) {
    protected[hello] def speak = println(greeting)
  }
  object Hello {
    def speak = new Greeting("Hello!!!!").speak
  }
}

Teraz obiekt Hi kompiluje się i można wywołać jego metodę hi.

scala> Hi.hi
Hi!!!!

W definicji metody speak kwalifikator [hello] jest potrzebny. Usunięcie go i pozostawienie samego modyfikatora protected powodowałoby błąd kompilacji obiektu Hello. Tak zmodyfikowany przykład znajduje się w pliku QualifiedProtected4.scala.

Plik QualifiedProtected4.scala:
package hello {
  class Greeting(greeting: String) {
    protected def speak = println(greeting)
  }
  object Hello {
    def speak = new Greeting("Hello!!!!").speak
  }
}

Kod z pliku QualifiedProtected4.scala nie kompiluje się.

$ scalac QualifiedProtected4.scala
QualifiedProtected4.scala:6: error: method speak in class Greeting cannot be accessed in hello.Greeting
 Access to protected method speak not permitted because
 enclosing object Hello in package hello is not a subclass of
 class Greeting in package hello where target is defined
    def speak = new Greeting("Hello!!!!").speak
                                          ^
one error found

Gdyby z pakietu hello usunąć definicję obiektu Hello, to nie tylko można by się pozbyć kwalifikatora [hello], ale nawet można by go zamienić na kwalifikator [this]. Ilustrują to przykłady w plikach QualifiedProtected5.scala i QualifiedProtected6.scala.

Plik QualifiedProtected5.scala:
package hello {
  class Greeting(greeting: String) {
    protected def speak = println(greeting)
  }
}
Plik QualifiedProtected6.scala:
package hello {
  class Greeting(greeting: String) {
    protected[this] def speak = println(greeting)
  }
}

Oba pliki kompilują się poprawnie wraz z plikiem QualifiedProtected2.scala.

$ scalac QualifiedProtected2.scala QualifiedProtected5.scala

$ scalac QualifiedProtected2.scala QualifiedProtected6.scala

$

Specyfikacja języka Scala opisuje modyfikator private w punkcie 5.2.1, a modyfikator protected w punkcie 5.2.2.

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.