Сегодня я решила вспомнить про static в Java. Что это вообще такое? Использование ключевого слова static можно сравнить с игрушкой для котиков. Независимо от того, кто из котиков с ней играет, игрушка остаётся в комнате и доступна всем котам. Каждый котик может подойти и начать играть с ней, но игрушка не становится его личной собственностью, она остаётся общей для всех.
Так и в Java, переменная или метод, объявленные как static, принадлежат всему классу, а не какому-то одному экземпляру этого класса. Это означает, что static элементы существуют в одном экземпляре всё время выполнения и принадлежат классу в целом, а не какому-либо конкретному объекту. Рассмотрим подробнее.
Static переменные:
Такие переменные инициализируются при загрузке класса и доступны до того, как будет создан любой объект класса.
Представим, что у нас есть класс котика Cat, в котором мы хотим считать количество котиков. Вместо того чтобы хранить эту информацию в каждом объекте Cat, мы можем использовать static переменную, которая будет общей для всех.
Теперь, независимо от количества созданных котиков, numberOfCats будет хранить их общее число.
Static методы:
Эти методы могут быть вызваны без создания экземпляра класса. Они могут взаимодействовать только со статическими переменными и вызывать только другие статические методы (потому что не статические поля связаны с конкретными объектами и их состоянием, а у нас объекта нет).
Пусть у нас есть метод, который должен печатать количество котиков.
Теперь мы можем вызывать Cat.displayNumberOfCats(), не создавая объект класса Cat.
Static блоки:
Иногда нам нужно инициализировать static данные до того, как будут созданы какие-либо объекты.
Статический блок выполняется один раз, когда класс загружается в JVM, аналогично простой инициализации, но перед любыми конструкторами объектов или методами класса.
Может возникнуть вопрос, а зачем нам статический блок, если можно создать переменную? Ключевое отличие в том, что в статическом блоке можно сделать какую-нибудь логику, добавить вычисления и т.п., что дает больше гибкости.
Статический класс:
Это вложенный класс, объявленный с использованием ключевого слова static. Обратите внимание, что речь идёт именно про вложенный класс. Мы не можем сделать класс котика Cat статичным.
Зачем нам вообще нужен вложенный класс?
- Вложенный статический класс не требует экземпляра внешнего класса для своего создания. Это означает, что он может быть создан и использован независимо от внешнего класса. Например, это полезно для вспомогательных классов, которые должны быть доступны без создания экземпляра внешнего класса.
- Вложенный статический класс может быть объявлен как private, что ограничивает его использование за пределами внешнего класса. Это полезно, когда вложенный класс должен использоваться только как вспомогательный компонент внешнего класса.
Статические импорты:
Если мы хотим напечатать имя собаки, то обычно мы просто используем Dog.name:
Но мы можем импортировать имя и тогда вызов будет просто name:
Плюсы static:
- Не нужно хранить один и тот же общий ресурс в каждом объекте. Экономия памяти.
- Лёгкое обращение к статическим методам и переменным просто по имени класса без создания объекта.
Минусы static:
- Статические переменные не могут быть переопределены в потомке. Мы можем создать методы с таким же названием, но тогда статический метод в родителе будет скрыт. Это не считается переопределением.
- Проблемы с тестированием: замокать статических классы и методы без сторонних библиотек довольно сложно.
- Глобальное состояние: static переменные могут неожиданно изменяться в любом месте приложения. Это усложняет рефакторинг, дебаг и расширение, потому что изменения в статических элементах могут затронуть огромное количество неожиданных мест в коде.
- Использование статических переменных для хранения глобального состояния может привести к неожиданным ошибкам, особенно в многопоточных приложениях, где разные потоки могут одновременно изменять одно и то же значение, вызывая состояние гонки и другие проблемы.
- Использование статических переменных может увеличить риск ошибок, связанных с безопасностью, так как такие переменные доступны в любой части приложения.
- В случаях, когда статические ресурсы требуют значительных вычислительных ресурсов или подключений к базе данных, то их непрерывное существование в течение всего жизненного цикла приложения может негативно сказаться на производительности.
Почему нельзя объявить метод интерфейса с модификатором static без реализации?
Описывая метод в интерфейсе мы говорим, что он должен быть реализован в классах и вызываться у объектов этих классов, что противоречит самому определению статика (статические методы могут вызываться просто по классу Cat, а не для конкретного барсика).
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes
P.S. сделано с помощью ChatGPT и Midjourney