Освой Java играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Ключевое слово static

Иногда требуется определить член класса, который будет использоваться независимо от любого объекта этого класса. И его можно использовать самостоятельно без ссылки на конкретный экземпляр. Для создания подобного члена класса, нужно в начало его объявления перед объявлением типа поместить ключевое слово static. В этом случае он становится доступен до создания каких-либо объектов его класса и без ссылки на какой-либо объект. Статическими могут быть и переменные и методы.

По существу переменные экземпляров, объявленные как static, являются глобальными переменными. При объявлении объектов их класса программа не создаёт никаких копий статической переменной. Вместо этого все экземпляры класса совместно используют одну и ту же статическую переменную.

У статических методов есть ряд ограничений:

  • они могут вызывать только другие статические методы
  • они могут непосредственно осуществлять доступ только к статическим переменным
  • они не могут ссылаться на члены типа this или super

В большинстве случаев среда разработки или компилятор заметят ошибку программиста и выведут предупреждение о неправильном использовании переменных.

Например, нельзя писать такой код.


public class HelloApp
{
    int number = 5; // ошибка -- следует добавить ключевое слово static
    
    public static void main(String[] args)
   {
       System.out.println(number); // не скомпилируется
    }
}

В статическом методе main() мы пытаемся задействовать нестатическую переменную number.

Также следите, чтобы не объявлять статическую переменную в статическом методе - так тоже нельзя.

Инициализирующий блок

Если для инициализации статических переменных требуется произвести вычисления, то для этой цели можно объявить инициализирующий блок, который будет выполняться только один раз при первой загрузке класса. Инициализирующий блок создаётся при помощи фигурных скобок и перед ними ставится ключевое слово static.

Любые инициализирующие блоки выполняются до конструкторов.

Создадим класс, который будет содержать статические переменные, статический метод и инициализирующий блок


class UsingStaticClass {
    // статические переменные
    static int a = 2;
    static int b;
    
    // инициализирующий блок
    static {
        b = a * 2;
    }
    
    // статический метод
    static void someMethod(int x) {
        Log.i(TAG, "x = " + x);
        Log.i(TAG, "a = " + a);
        Log.i(TAG, "b = " + b);        
    }
}

За пределами класса, в котором они определены, статические методы и переменные могут использоваться независимо от какого-либо объекта. Для этого достаточно указать имя класса, затем точку, а потом имя метода или переменной:

имя_класса.метод()
имя_класса.переменная

В Android имеются много статических методов и переменных. Например, метод Log.i(). Так как метод является статическим, мы не объявляем Log log = new Log(). Достаточно сразу вызвать метод.


Log.i(TAG, "Кот отказался мяукать");

Также часто используется статический метод Toast makeText().

Статическая переменная

Чтобы лучше уяснить механизм работы статической переменной, напишем следующий пример. Создадим класс Cat.


package ru.alexanderklimov.expresscourse;

public class Cat {
    private String mName;
    private int mAge;
    static int sId = 0;
    static int sTestNumber = 8;

    public Cat(String name, int age) {
        mName = name;
        mAge = age;
        sId++;
    }

    @Override
    public String toString() {
        return this.mName;
    }
}

Мы создали две статические переменные. Одну не трогаем, а вторую увеличиваем на единицу в конструкторе.

Переходим в класс активности и проверяем, чему равны эти переменные.


Log.d(TAG, Cat.sId + "");
Log.d(TAG, Cat.sTestNumber + "");

Программа вернёт значения, которые мы сами установили - 0 и 8. Обратите внимание, чтоб мы даже не создавали экземпляры класса, а обращались напрямую к классу.

А теперь создадим двух котов с именами и возрастом. А между котами явно увеличим одну статическую переменную. И снова проверим значения статических переменных.


Log.d(TAG, Cat.sId + "");
Log.d(TAG, Cat.sTestNumber + "");

// Создаём первого кота
Cat firstCat = new Cat("vasya", 2);
Log.d(TAG, Cat.sId + "");
Log.d(TAG, Cat.sTestNumber + "");

Cat.sTestNumber = 15; // устанавливаем новое значение
// Создаём второго кота
Cat secondCat = new Cat("murzik", 12);
Log.d(TAG, Cat.sId + "");
Log.d(TAG, Cat.sTestNumber + "");

Получим результат.


0
8
1
8
2
15

Первые два значения понятны из предыдущего примера. Затем при создании первого кота, переменная sId автоматически увеличивается на единицу. Вторая переменная остаётся без изменений.

Затем мы явно указываем новое значение для второй переменной, и создаём второго кота, у которого также сработает увеличение на единицу первой переменной. Проверка убедит нас в этом. Было 1 и 8, стало 2 и 15.

Вариант с автоматическим увеличением иногда используют для создания уникального идентификатора объекта, например, товара в магазине. Заводя новый товар, мы автоматически получаем его новый номер, используя статическую переменную.

Реклама