Модифікатори в java - огляд і приклади використання
Всім привіт. Сьогодні ми розглянемо модифікатори в Java.
Модифікатор - це ключове слово мови, яке може будь-яким чином змінити зміст деякого визначення (наприклад, класу або методу). Серед всіх модифікаторів окремо виділяють групу модифікаторів доступу:
- public;
- protected;
- модифікатор за замовчуванням - його ще називають package;
- private.
Про модифікатори доступу я детально напишу в статті про ООП в Java. А на зараз план такий:
Модифікатори класів (class modifiers)
Модифікатор abstract. застосований до класу, говорить про те, що клас є (або вважається) незакінченою, а завдання "завершити" клас покладається на спадкоємців. Спроба інстанцііровать такий клас призведе до помилки компіляції, наприклад:
В результаті компіляції цього коду отримаємо помилку: Expression is abstract; can not be instantiated.
Зверніть увагу, у абстрактного класу не обов'язково повинні бути абстрактні методи.
Модифікатор final у класу говорить про те, що від нього не можна успадковуватися.
Спроба компіляції коду призведе до помилки: can not inherit from final Example.
Очевидно, клас не можна оголосити одночасно final і abstract.
Вкладені класи в Java можуть бути оголошені як static. наприклад:
В цьому випадку клас називається статичним вкладеним класом і має доступ до статичних полів і методів обрамляє класу.
Модифікатори методів (method modifiers)
З методами варіантів небагато більше. Методи в Java можуть бути оголошені як abstract, final, static, strictfp (читайте в кінці статті), native, synchronized.
Метод з модифікатором abstract може бути оголошений як метод-член (member method) в межах абстрактного класу (або інтерфейсу). В цьому випадку тіло методу відсутня, а реалізація може бути надана в класах-спадкоємців. Якщо ж метод оголошений як абстрактний в конкретному класі, то отримаємо помилку компіляції.
Метод, оголошений з модифікатором final не може бути перевизначений в спадкоємців.
У наведеному прикладі виникне помилка на етапі компіляції: a () in Clazz.SubClass can not override a () in Clazz; overridden method is final
Метод з модифікатором static відноситься до класу в цілому, а не до його екземплярів, тобто в нього не передається об'єкт this. Такий метод може бути викликаний використовуючи ім'я класу. наприклад:
Нарешті, модифікатор synchronized у методу говорить про те, що перед його виконанням повинен бути захоплений монітор об'єкта (для нестатичних методу), або монітор, пов'язаний з класом (для статичного методу).
Ось невеликий приклад коду, який демонструє опис синхронізованих методів. Захоплення монітора так само здійснюється за допомогою ключового слова synchronized.
Модифікатори полів (field modifiers)
Перейдемо до полів класів. Вони можуть бути описані з такими модифікаторами як static, final, transient, volatile.
Якщо поле класу оголошено як static. то буде існувати рівно одне значення цього поля, не залежно від того, скільки примірників класу буде створено, навіть якщо не буде створено жодного примірника. Такі статичні поля ще називають змінними рівня класу (class variable).
Поле з модифікатором final не може поміняти свого значення після ініціалізації. Це стосується і статичних, і нестатичних полів (member fields).
Компіляція цього коду призведе до помилки: can not assign a value to final variable constant.
Для вказівки того, що під час сериализации об'єкта деяке поле потрібно ігнорувати, використовується модифікатор transient. Зазвичай такі поля не є частиною внутрішнього стану об'єкта, або зберігають проміжні значення.
З модифікатором volatile все трохи складніше. Спробую пояснити простіше. В Java потоки можуть зберігати значення деяких змінних в деякій своєму локальному контексті. Якщо один потік змінить значення такого поля, то інший потік може про це не впізнати (так як зберігає копію). Для полів з модифікатором volatile є гарантія, що всі потоки завжди бачитимуть актуальне значення такої змінної.
Модифікатори, пов'язані з інтерфейсами
До інтерфейсів можна застосувати ті ж модифікатори, що і до класів, природно крім final. Інтерфейс є abstract за замовчуванням. У випадку зі вкладеним інтерфейсом ключове слово static можна не вказувати - він в будь-якому випадку буде статичним.
Методи інтерфейсів по-умлочанію є public abstract, тому до них не застосовні модифікатори final, static і native. Синхронізованими вони теж бути не можуть, так як інтерфейс можна інстанцііровать.
Поля інтерфейсів за замовчуванням є public static final, а значить повинні бути проініціалізовані.
Якщо підсумувати, то два фрагмента коду нижче є ідентичними:
Ну і default - остання розробка в області модифікаторів :). Метод інтерфейсу, позначений як default, надає реалізацію цього методу за замовчуванням. наприклад:
Цей код скомпілюється без помилок на Java версії 1.8.
Інші контексти використання модифікаторів
Є ще 2 варіанти, де можуть використовуватися модифікатори.
Перший варіант - це локальні змінні, які можуть бути оголошені як final. У цьому випадку значення змінної не можна буде змінити в в межах методу після ініціалізації
Другий варіант - це статичний блок ініціалізації, який виконується при завантаженні класу:
Ну і нарешті, перейдемо до модифікатору strictfp. Модифікатор strictfp для класу і інтерфейсу вказує на те, що всі методи класу / інтерфейсу будуть strictfp. Ну а якщо метод описаний як strictfp (явно або неявно), то JVM гарантує, що результати обчислення виразів з double і float в межах методу будуть однаковими на всіх платформах.
Даний модифікатор був введений у версії Java 1.2. Але зараз всі сучасні компілятори самі проставляють цей модифікатор, так що з приводу переносимості ваших програм можете бути спокійні.