1. Константи

У багатьох мовах програмування є константизмінні, значення яких змінювати не можна. Зазвичай це якісь фундаментальні речі на кшталт числа Pi або кількості днів у місяцях. Хоча в принципі програміст може зробити будь-яку змінну константою, якщо вважатиме це за потрібне.

Отже, як оголосити незмінювану змінну (константу) в Java? Для цього є спеціальне ключове слово — final. Створення незмінюваної змінної має такий самий вигляд, як і створення звичайної, тільки перед типом змінної слід написати слово final:

final тип ім'я = значення;

Якщо ви спробуєте присвоїти final-змінній інше значення, ваша програма просто не скомпілюється.

final-змінну обов'язково треба ініціалізувати (присвоїти їй значення) під час оголошення. Це правило має один виняток: можна перенести ініціалізацію змінної класу в конструктор. Однак про це ви дізнаєтеся на 10-му рівні.

Щоб зменшити кількість ключових слів, розробники Java використовують слово final не тільки для оголошення констант. Метод і навіть клас теж можуть бути final. Методи, оголошені як final, не можна перевизначати (override), а клас, оголошений як final, не може бути базовим класом для успадкування.

Модифікатор final можна вказувати перед будь-якими змінними: локальними, параметрами, полями класу і статичними змінними.

Зверніть увагу, що final — це лише захист від змінення змінної. Якщо змінна зберігає посилання на об'єкт, то об'єкт все ж таки міняти можна.

Приклад:

final int[] data = {1, 2, 3, 4, 5, 6};

data = {6, 7, 8, 9};

data[0] = 0;
data[1] = 0;
data[2] = 0;
Створюємо масив.

Так не можна: змінну data оголошено як final.

А так можна.
І так можна.

Глобальні константи

Якщо ви захочете оголосити у своїй програмі глобальні константи, вам потрібно створити статичні змінні класу, а також визначити їх як public і final. Для імен таких змінних існує спеціальний стиль написання: їх пишуть великими літерами, а як роздільник слів використовують знак підкреслення.

Приклади:

class Solution
{
   public static final String SOURCE_ROOT = "c:\\projects\\my\\";
   public static final int DISPLAY_WIDTH = 1024;
   public static final int DISPLAY_HEIGHT = 768;
}


2. Затінення змінних

Як ми вже казали, не можна в одному методі створити кілька локальних змінних з однаковими іменами. У різних методах — можна.

А цього ви, напевно, не знаєте: змінним класу і локальним змінним методу дозволено мати однакові імена.

Приклад:

Код Доступність змінних
public class Solution
{
   public int count = 0;
   public int sum = 0;

   public void add(int data)
   {
     sum = sum + data;
     int sum = data * 2;
     count++;
   }
}


count
count, sum
count, sum
count, sum
count, sum, data
count, sum, data
count, sum, data
count, sum, data
count, sum

У методі add ми оголосили локальну змінну sum, і вона до кінця дії методу перекриває (або ще кажуть затіняє) собою змінну класу sum.

Ну гаразд, скажете ви, навіть в якомусь сенсі очікувана поведінка. Але це ще не все. Виявляється, якщо змінну класу затіняє локальна змінна, у методі все-таки є спосіб звернутися до змінної класу. Для цього потрібно перед її іменем написати ключове слово this:

this.ім'я

Ось приклад, в якому конфлікт імен успішно вирішується:

Код Доступність змінних
public class Solution
{
   public int count = 0;
   public int sum = 0;

   public void add(int data)
   {
     int sum = data * 2;
     this.sum = this.sum + data;
     count++;
   }
}


this.count
this.count, this.sum
this.count, this.sum
this.count, this.sum
this.count, this.sum, data
this.count, this.sum, data, sum
this.count, this.sum, data, sum
this.count, this.sum, data, sum
this.count, this.sum

Змінні count і sum доступні всюди як із ключовим словом this, так і без нього. У тих рядках, де локальна змінна sum затіняє змінну класу sum, доступ до змінної класу sum можливий тільки за умови застосування this.

Якщо затіняється не просто змінна класу, а статична змінна класу, звертатися до неї потрібно не через this, а через ім'я класу:

ClassName.ім'я

Приклад:

Код Доступність змінних
public class Solution
{
   public static int count = 0;
   public static int sum = 0;

   public void add(int data)
   {
     int sum = data * 2;
     Solution.sum = Solution.sum + data;
     count++;
   }
}

Solution.count, Solution.sum
Solution.count, Solution.sum
Solution.count, Solution.sum
Solution.count, Solution.sum
Solution.count, Solution.sum
Solution.count, Solution.sum, data
Solution.count, Solution.sum, data, sum
Solution.count, Solution.sum, data, sum
Solution.count, Solution.sum, data, sum
Solution.count, Solution.sum

Статичні змінні count і sum доступні всюди як із префіксом у вигляді імені класу Solution, так и без нього. У тих рядках, де локальна змінна sum затіняє змінну класу sum, доступ до змінної класу sum можливий тільки за умови застосування префікса Solution.



3. Змінні всередині циклу for

І ще один маленький, але цікавий факт.

Є ще одне місце, де в особливий спосіб оголошується змінна — це цикл for.

Якщо ви пам'ятаєте, зазвичай у циклі for в круглих дужках оголошується змінна-лічильник. І яка ж буде область видимості цієї змінної? Адже вона не міститься в тілі циклу — значить, її буде видно по всьому методу? Чи все-таки ні?

Правильна відповідь така: змінну, оголошену в заголовку циклу for, видно лише в тілі циклу і в заголовку циклу for.

Приклад:

Код Доступність змінних
public static void main(String[] args)
{
   int a = 0;

   for (int i = 0; i < 10; i++)
   {
     System.out.println(i);
   }

   System.out.println("end");
}


a
a
a, i
a, i
a, i
a
a
a

Отож ви завжди можете в своєму коді послідовно написати кілька циклів зі змінною-лічильником із однаковим іменем — проблем не буде.

Приклад:

Код Доступність змінних
public static void main(String[] args)
{
   int a = 0;

   for (int i = 0; i < 10; i++)
   {
     System.out.println(i);
   }

   for (int i = 0; i < 10; i++)
   {
     System.out.println(i);
   }

   System.out.println("end");
}


a
a
a, i
a, i
a, i
a
a
a, i
a, i
a, i
a
a
a