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 = new int[]{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