Модификаторы доступа Scala
В Scala модификаторы доступа используются для управления видимостью и правами доступа классов, объектов, трейтов и их членов (таких как поля и методы).
Модификаторы доступа Scala в основном такие же, как в Java: private, protected и public.
Если модификатор доступа не указан, по умолчанию уровень доступа в Scala — public.
Квалификатор private в Scala строже, чем в Java. В случае вложенных классов внешний класс не может даже получить доступ к private-членам вложенного класса.
Закрытые члены
Члены, помеченные ключевым словом private, видны только внутри класса или объекта, содержащего определение члена. То же правило также применяется к внутренним классам.
Пример
class Inner{
private def f(){
println("f")
}
class InnerMost{
f() // Верно
}
}
(new Inner).f() // Ошибка
}
(new Inner).f( )Доступ запрещён, потому чтоfон объявлен как private в Inner, а доступ осуществляется не внутри класса Inner.
Но доступ к нему в InnerMostfдопустим, потому что этот доступ осуществляется внутри класса Inner.
Java позволяет оба доступа, потому что позволяет внешним классам получать доступ к private-членам внутренних классов.
Защищённые члены
В Scala доступ к protected-членам строже, чем в Java. Он позволяет обращаться к protected-членам только в подклассах класса, в котором определён член. В Java к членам, модифицированным ключевым словом protected, могут обращаться подклассы класса, определяющего член, а также другие классы в том же пакете.
Пример
class Super {
protected def f() {println("f")}
}
class Sub extends Super {
f()
}
class Other {
(new Super).f() // Ошибка
}
}
В приведённом выше примере доступ класса Sub к f допустим, потому что f объявлен protected в Super, а Sub является подклассом Super. Напротив, доступ Other к f не разрешён, потому что Other не наследует от Super. Последнее также разрешено в Java, потому что Other и Sub находятся в одном пакете.
Публичные члены
В Scala, если модификатор не указан, по умолчанию используется public. К таким членам можно обращаться где угодно.
Пример
class Inner {
def f() { println("f") }
class InnerMost {
f() // Верно
}
}
(new Inner).f() // Верно, потому что f() является общедоступным
}
Доступ package-private
Scala также поддерживает модификатор доступа package-private, который делает члены доступными только внутри конкретного пакета. Для этого после ключевого слова private указывается имя пакета. Формат таков:
private[x] или protected[x]
Здесьxозначает пакет, класс или singleton-объект, к которому он принадлежит.
Если записать какprivate[x], это читается так:"Этот член является приватным для всех остальных классов, кроме классов в […] или классов в пакете […] и их объектов-компаньонов."。
Этот приём очень полезен в больших проектах, охватывающих несколько пакетов. Он позволяет определять сущности, видимые в нескольких подпакетах вашего проекта, но остающиеся невидимыми для клиентов вне проекта.
Пример
package navigation{
private[bobsrockets] class Navigator{
protected[navigation] def useStarChart(){}
class LegOfJourney{
private[Navigator] val distance = 100
}
private[this] var speed = 200
}
}
package launch{
import navigation._
object Vehicle{
private[launch] val guide = new Navigator
}
}
}
В приведённом выше примере класс Navigator помечен как private[bobsrockets], что означает, что этот класс виден всем классам и объектам, содержащимся в пакете bobsrockets.
Например, доступ к Navigator из объекта Vehicle разрешён, потому что объект Vehicle содержится в пакете launch, а пакет launch находится в bobsrockets. И наоборот, любой код за пределами пакета bobsrockets не может получить доступ к классу Navigator.
Объекты-компаньоны и классы-компаньоны
В Scala объекты-компаньоны и классы-компаньоны могут получать доступ к приватным членам друг друга. Объект-компаньон и его класс-компаньон — это класс и объект с одинаковым именем в одном и том же файле.
Пример
private val privateField: String = "I am private in class"
}
object CompanionExample {
def accessPrivateField(example: CompanionExample): String = {
example.privateField // Объект-компаньон может обращаться к приватным членам класса
}
}
object Main {
def main(args: Array[String]): Unit = {
val example = new CompanionExample
println(CompanionExample.accessPrivateField(example))
}
}