W3docs

Модификаторы доступа в Java

Управляйте видимостью в Java с помощью модификаторов доступа public, private, protected и package-private (по умолчанию).

Модификаторы доступа определяют, кто может видеть и использовать класс, поле, метод или конструктор. В Java существует четыре уровня — public, protected, package-private (без ключевого слова) и private — от «доступно всем» до «только этот класс». Правильный выбор модификатора позволяет провести границу между интерфейсом объекта и его внутренней реализацией.

Четыре уровня

От наименее ограничительного к наиболее ограничительному:

МодификаторВидимость
publicОткуда угодно
protectedТот же пакет или любой подкласс (даже из другого пакета)
(без ключевого слова)Только тот же пакет — package-private
privateТолько сам класс

Это всё. Никакого «friend», никакого «module-internal» на этом уровне; видимость модулей — это отдельная возможность Java Platform Module System, которая в большинстве случаев не нужна.

public

Член с модификатором public является частью опубликованного API класса — он виден любому коду, который имеет доступ к самому классу:

public class Greeter {
  public String greet(String name) {
    return "Hello, " + name;
  }
}

new Greeter().greet("world");    // anyone can call this

Используйте public для тех элементов, которые предназначены для вызова другим кодом — даже из других проектов. Обратная сторона: как только что-то становится public, вы берёте на себя обязательство его поддерживать; изменение сигнатуры сломает всех вызывающих.

private

private ограничивает видимость члена только объявляющим классом. Ничто извне не может его использовать — даже подкласс:

public class Account {
  private int balance;     // only Account can read/write

  public void deposit(int amount) {
    if (amount <= 0) throw new IllegalArgumentException();
    balance += amount;      // ok — same class
  }
}

Account a = new Account();
a.balance = -1;             // ERROR — balance is private

Это основной модификатор для полей. Скрытие состояния за private делает проверку в методе deposit действительно значимой. Паттерн подробно описан в главе об инкапсуляции.

Package-private (без ключевого слова)

Если модификатор не указан вовсе, член виден всему коду в том же пакете — но не за его пределами:

// in package com.shop
class CartHelper {           // no public — package-private
  static int sum(int[] prices) { ... }
}

Другие классы в com.shop могут вызывать CartHelper.sum(...); код в com.app не увидит даже существования этого класса. Используйте этот уровень для внутренних вспомогательных элементов, которые нужны внутри пакета, но не должны быть частью внешнего API проекта.

Распространённая ошибка: забыть указать модификатор, а затем удивляться, что класс доступен из main (тоже находящегося в том же пакете во время обучения), но недоступен из теста в другом пакете.

protected

protected — это package-private плюс подклассы. Код в том же пакете может использовать член, и любой подкласс — даже из другого пакета — тоже может его использовать:

public class Shape {
  protected double area;       // subclasses can read/write
}

public class Circle extends Shape {
  Circle(double r) {
    this.area = Math.PI * r * r;   // ok — subclass access
  }
}

Этот модификатор нужен, когда вы хотите, чтобы подклассы могли подключаться к механизмам родителя, но не хотите, чтобы к ним мог обратиться произвольный клиентский код. На практике protected встречается намного реже, чем public или private; многие разработчики предпочитают использовать private-поля с protected-методами доступа для аналогичного эффекта с большим контролем.

Где применяются модификаторы

Модификатор можно указать для:

  • Класса (public class Foo). Классы верхнего уровня могут быть только public или package-private. Вложенные классы могут использовать любой из четырёх модификаторов.
  • Поля (private int count).
  • Метода (public int get() {...}).
  • Конструктора (private Singleton() {...} — см. паттерн Singleton).

Модификатор доступа нельзя указать для локальной переменной или параметра метода. Их область видимости определяется исключительно местом объявления.

Правило «один public-класс на файл»

Файл .java может содержать несколько классов верхнего уровня, но не более одного из них может быть public, и его имя должно совпадать с именем файла:

// file: Order.java
public class Order { ... }          // ok — matches filename
class OrderHelper { ... }           // ok — package-private
public class Customer { ... }       // ERROR — second public class

Большинство проектов придерживаются правила «один класс на файл», однако package-private вспомогательные классы рядом с public-классом иногда бывают полезны.

Как выбрать правильный модификатор

Практическое правило, которое хорошо масштабируется:

  1. По умолчанию используйте private для полей и вспомогательных методов.
  2. public для методов, которые действительно должны вызываться извне.
  3. Package-private для элементов, которые нужно разделить внутри пакета, но не раскрывать за его пределами.
  4. protected только тогда, когда нужен доступ из подклассов.

Расширить доступ позже (privatepublic) легко; сузить его без нарушения совместимости — болезненно. Начинайте с самого ограничительного.

Модификаторы не влияют на поведение

Модификатор доступа — это проверка на этапе компиляции. Во время выполнения два одинаковых поля типа int ведут себя одинаково, независимо от того, объявлены ли они public или private. Модификатор существует исключительно для того, чтобы не дать другому коду скомпилироваться с использованием данного члена — для соблюдения границы, которую вы объявляете.

Рабочий пример

java— editable, runs on the server

Что дальше

public, protected, private — это модификаторы доступа. В Java есть ещё одно семейство — неакцессорные модификаторы, такие как static, final, abstract, synchronized — они управляют поведением, а не видимостью. Следующая глава, неакцессорные модификаторы, посвящена обзору этих возможностей.

Практика

Практика
Поле объявлено без модификатора доступа — просто int count;. Кто может его читать?
Поле объявлено без модификатора доступа — просто int count;. Кто может его читать?
Was this page helpful?