У java є ключове слово –
final
. Воно може застосовуватися до класів, методів, змінних (у тому числі аргументів методів). Для класу це, що клас зможе мати підкласів, тобто. заборонено наслідування. Це корисно при створенні immutable
(незмінюваних) об'єктів, наприклад, клас String
оголошений як final
.
public final class String{
}
class SubString extends String{ //Помилка компіляції
}
Слід зазначити, що з абстрактним класам (з ключовим словом abstract
), не можна застосувати модифікатор final
, т.к. це взаємовиключні поняття. Для методу final
означає, що він не може бути перевизначений у підкласах. Це корисно, коли хочемо, щоб вихідну реалізацію не можна було перевизначити.
public class SuperClass{
public final void printReport(){
System.out.println("Report");
}
}
class SubClass extends SuperClass{
public void printReport(){ //Помилка компіляції
System.out.println("MyReport");
}
}
Для змінних примітивного типу це означає, що одного разу надане значення не може бути змінено. Для змінних посилання це означає, що після присвоєння об'єкта, не можна змінити посилання на цей об'єкт. Це важливо! Посилання змінити не можна, але можна змінити стан об'єкта. З java 8 з'явилося поняття effectively final
. Застосовується воно лише до змінних (зокрема аргументів методів). Суть у тому, що незважаючи на явну відсутність ключового слова final
, значення змінної не змінюється після ініціалізації. Інакше кажучи, до такої змінної можна підставити слово final
без помилки компіляції. effectively final
змінні можуть бути використані всередині локальних класів ( Local Inner Classes
), анонімних класів ( Anonymous Inner Classes
), стриму (Stream API).
public void someMethod(){
// У прикладі нижче і a і b - ефективно final, тк значення встановлюються одного разу:
int a = 1;
int b;
if (a == 2) b = 3;
else b = 4;
// з НЕ є ефективним final, т.к. значення змінюється
int c = 10;
c++;
Stream.of(1, 2).forEach(s-> System.out.println(s + a)); //Ок
Stream.of(1, 2).forEach(s-> System.out.println(s + c)); //Помилка компіляції
}
А тепер давайте влаштуємо невелику співбесіду. Адже заснована мета проходження курсу JavaRush - це стати Java розробником і влаштуватися на цікаву роботу, що добре оплачується. Тож почнемо.
-
Що можна сказати про масив, коли він оголошений
final
? -
Відомо, що клас
String
-immutable
, клас оголошенийfinal
, значення рядка зберігається в масивіchar
, який відзначений ключовим словомfinal
.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
Чи можна замінити значення об'єкта String
(не змінюючи посилання на об'єкт)? Це реальні питання із співбесіди. І як показує практика, багато хто відповідаю на них не правильно. Розуміння використання ключового слова final
, особливо для посилальних змінних – дуже важливе. Поки ви розмірковуєте, невеликий відступ до команди JavaRush. Прохання додати в текстовому редакторі блок, що дозволяє приховувати вміст, а при натисканні по ньому — показувати цей вміст. Відповіді:
-
Т.к. масив – це об'єкт, це
final
означає, що після присвоєння посилання об'єкт, не можна її змінити, але можна змінювати стан об'єкта.final int[] array = {1,2,3,4,5}; array[0] = 9; //Ок, т.к. змінюємо вміст масиву - {9,2,3,4,5} array = new int[5]; //помилка компіляції
-
Так можна. Ключовий момент – це розуміння використання колючого слова
final
із об'єктами. Для заміни значення використовує ReflectionAPI.
import java.lang.reflect.Field;
class B {
public static void main(String[] args) throws Exception {
String value = "Old value";
System.out.println(value);
//Отримуємо поле value у класі String
Field field = value.getClass().getDeclaredField("value");
// Дозволяємо змінювати його
field.setAccessible(true);
//Встановлюємо нове значення
field.set(value, "JavaRush".toCharArray());
System.out.println(value);
/* Вывод:
* Old value
* JavaRush
*/
}
}
Зверніть увагу, що якби ми спробували змінити подібним чином фінальну змінну примітивного типу, то нічого не вийшло б. Пропоную вам самостійно переконати в цьому: створити Java клас, наприклад, з final int
полем і спробувати змінити його значення через Reflection API. Всім удачі!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ