Принадлежность классу, а не объекту
Большинство полей и методов, которые вы писали до сих пор, принадлежат объектам: каждый раз, когда вы вызываете new, каждый экземпляр получает собственную копию полей, а методы работают с состоянием конкретного объекта. Ключевое слово static переворачивает это. static-член принадлежит самому классу — существует одна-единственная копия, общая для всех экземпляров, и она существует независимо от того, создадите ли вы хоть один объект.
Это единственное различие объясняет static-поля, static-методы, константы и даже то, почему main всегда static.
Общее static-поле
Нестатическое поле даёт каждому объекту собственную ячейку. static-поле даёт классу одну ячейку, общую для всех. Классический пример — счётчик, отслеживающий, сколько объектов было создано:
Обратите внимание, что вы читаете счётчик как User.count — через имя класса, потому что значение не принадлежит ни одному конкретному User. Каждое name, напротив, живёт внутри своего объекта. Измените count через любой экземпляр — и все экземпляры увидят новое значение, потому что оно одно.
static-методы
static-метод тоже принадлежит классу, поэтому вы вызываете его на классе без объекта:
Именно этот приём лежит в основе стандартной библиотеки: Math.max, Integer.parseInt, Arrays.sort и List.of — все они static, это служебное поведение, которому не нужен объект для работы. Прибегайте к static-методу, когда работа зависит только от аргументов, а не от состояния какого-либо объекта.
Главная ловушка: static не видит instance
static-метод выполняется без какого-либо объекта, поэтому this отсутствует. Это значит, что он не может напрямую обращаться к полям экземпляра или вызывать методы экземпляра — нет конкретного объекта, из которого их прочитать. Это самая частая ошибка новичков со static:
class Account {
int balance = 100; // поле экземпляра
static int show() {
return balance; // ОШИБКА КОМПИЛЯЦИИ: к нестатическому полю 'balance'
} // нельзя обратиться из статического контекста
}
Исправление: либо сделать метод методом экземпляра (убрать static, чтобы у него появился this), либо передать объект явно:
Обратное направление работает без проблем: метод экземпляра может свободно читать static-поля и вызывать static-методы, потому что общие данные уровня класса существуют всегда.
Константы со static final
Сочетайте static с final — и получите константу: одно общее значение, которое никогда не может измениться. По соглашению их называют в стиле UPPER_SNAKE_CASE:
static final — идиоматичный способ выразить «фиксированное значение, принадлежащее типу», как, например, Integer.MAX_VALUE или Math.PI в стандартной библиотеке. Сделать его static — значит не тратить по копии на каждый объект; сделать его final — значит никто не сможет его переприсвоить.
Статические блоки инициализации
Простое static-поле можно инициализировать прямо в строке объявления. Когда настройка требует настоящей логики — построить таблицу поиска, прочитать конфигурацию — используйте static-блок. Он выполняется один раз, при первой загрузке класса, до того как появится хоть один объект:
Блок срабатывает ровно один раз, сколько бы раз вы ни использовали класс, что делает его подходящим местом для разовой настройки в масштабе всего класса.
Когда использовать static
Быстрое правило:
- Используйте static-поле только для данных, которые действительно общие для всех экземпляров — счётчик, кеш, константа. Если два объекта могут разумно хранить разные значения, это должно быть поле экземпляра.
- Используйте static-метод, когда результат зависит только от аргументов, а не от состояния какого-либо объекта (чистые служебные функции).
- По умолчанию выбирайте члены экземпляра. Злоупотребление
staticнезаметно превращает программу в кучу глобального состояния, которое трудно тестировать и понимать.static— это исключение, а не отправная точка.
Далее: перечисления (Enum)
Константа static final хороша для одного фиксированного значения, но когда у вас есть небольшой фиксированный набор связанных значений — направления, дни недели, статусы заказа — в Java есть специально созданный тип, более безопасный и выразительный, чем разрозненные константы. Это enum, и о нём — следующая страница.
Часто задаваемые вопросы
Что означает static в Java?
static означает, что поле или метод принадлежит самому классу, а не отдельному объекту. Существует ровно одна копия static-поля, общая для всех экземпляров, и static-метод вызывается на классе (Math.max(...)) без необходимости в объекте. Нестатические члены (экземпляра), напротив, получают новую копию для каждого объекта.
В чём разница между static-переменными и переменными экземпляра в Java?
У переменной экземпляра есть одно значение на объект — два объекта могут хранить разные значения. У static-переменной единственное значение, общее для всех объектов класса, поэтому её изменение через один объект (или через имя класса) видно всем остальным. Используйте поля экземпляра для состояния, своего у каждого объекта, и static-поля для данных, по-настоящему общих для всего класса, например счётчика или константы.
Почему метод main в Java объявлен static?
JVM должна вызвать main до того, как появится хоть один объект вашего класса. Поскольку static-метод принадлежит классу, а не экземпляру, среда выполнения может напрямую вызвать Main.main(args), не создавая сначала Main. Именно поэтому сигнатура всегда выглядит как public static void main(String[] args).