Инициализация статических членов данных. Статический блок. Инициализация массивов

Инициализация статических членов данных. Статический блок. Инициализация массивов


Содержание



1. Инициализация статических членов данных. Каким образом инициализируются статические члены данных?

Если в классе объявлен статический член данных, то он всегда существует в одном экземпляре, независимо от количества создаваемых объектов класса. Статический член данных может быть объявлен как член данных класса:

class MyClass
{
    static int d; // статический член данных класса
    static float x; // статический член данных класса

    ...
}

Если статический член данных примитивного типа не инициализирован в классе, то нему присваивается значение по умолчанию. Если статический член данных есть ссылкой на объект, то нему присваивается значение null.

Ниже приведены значения по умолчанию, которые присваиваются статическим членам данных в случае отсутствия явной инициализации

static int i; // i = 0
static boolean b; // b = false
static float f; // f = 0.0
static double d; // d = 0.0
static char c; // c = символ с кодом 0
static CDate objDate; // objDate = null

Если нужно осуществить явную инициализацию статического члена данных в месте его объявления, тогда это осуществляется точно так же как и для нестатического члена данных:

class MyClass
{
    static int d = 25; // инициализация статического члена данных конкретным значением
    static float x = 108.35;

    ...
}

Более подробно работа со статическими членами данных в Java освещается в теме:

2. Пример инициализации статических членов данных класса. Инициализация статического члена данных с помощью метода

В примере объявляется два класса с именами CDate и CStaticData. В классе CStaticData статические члены данных класса инициализируются так же как и нестатические члены данных класса.

// инициализация статических членов данных класса
public class CStaticData
{
    // инициализация статических членов класса
    static int i = 2588;
    static boolean b = true;
    static float f = 3.23f;
    static double d = -10.2093;

    // инициализация статического объекта (экземпляра) класса
    static CDate objDate = new CDate();

    // инициализация статического члена класса с помощью метода класса GetPi()
    static double Pi = GetPi(); // метод GetPi() класса также может быть статическим
    static double GetPi() { return 3.1415; }

    public static void main(String[] args)
    {
        CStaticData obj = new CStaticData();
        obj.b = false;
        CStaticData.d = -10.223;
    }
}

Как видно из примера, чтобы инициализировать статический член данных класса Pi с помощью метода GetPi(), этот метод может быть также объявлен как статический.

3. Какой порядок инициализации, если в классе объявляются статические и нестатические члены данных класса?

Если в классе объявляются статические и нестатические члены данных класса, то первыми инициализируются статические члены данных класса. После этого инициализируются нестатические члены данных класса.

Пример. Объявляется класс CDataInit, в котором в произвольном порядке инициализируются статические и нестатические члены данных класса.

public class CDataInit
{
    // внутренние функции, которые используется при инициализации
    int GetInt(String s)
    {
        System.out.println("Non-static initialization of " + s);
        return 100;
    }

    static int GetIntStatic(String s)
    {
        System.out.println("Static initialization of " + s);
        return 5;
    }

    // переменные, которые должны быть инициализированы - объявлены в произвольном порядке
    int i1 = GetInt("i1");
    static int si1 = GetIntStatic("si1");
    int i2 = GetInt("i2");
    int i3 = GetInt("i3");
    static int si2 = GetIntStatic("si2");
    int i4 = GetInt("i4");
    static int si3 = GetIntStatic("si3");

    public static void main(String[] args)
    {
        CDataInit obj = new CDataInit();
    }
}

После объявления объекта класса CDataInit выводятся следующие строки:

Static initialization of si1
Static initialization of si2
Static initialization of si3
Non-static initialization of i1
Non-static initialization of i2
Non-static initialization of i3
Non-static initialization of i4

Как видно из приведенного выше результата, первыми инициализируются статические члены данных.

4. Что такое статический блок? Общая форма

Статический блок – это специальная конструкция, которая помогает сгруппировать несколько действий, предназначенных для инициализации статических членов данных.

Общая форма статического блока:

static
{
    // операции, которые инициализируют статические члены класса
    // ...
}

В классе статический блок выглядит приблизительно следующим образом:

class ClassName
{
    ...

    static
    {
        // инициализация статических членов данных класса
        // ...
    }

    ...
}

5. Пример использования статического блока

В классе CDataInit объявляется статический блок, в котором инициализируются статические переменные a, b, c, d.

public class CDataInit
{
    static int a, b, c, d;

    // инициализация с помощью статического блока
    static
    {
        a = 1;
        b = 2;
        c = 3;
        d = 4;
    }

    public static void main(String[] args)
    {
        CDataInit obj = new CDataInit();
        int t;

        // проверка
        t = obj.a; // t = 1
        t = obj.b; // t = 2
        t = obj.c; // t = 3
        t = obj.d; // t = 4
    }
}

6. Сколько раз вызывается статический блок? В каких случаях вызывается статический блок?

Статический блок вызывается только один раз в одном из двух случаев:

  • при первом создании объекта этого класса;
  • при первом обращении к статическим членам этого класса.

Пример. Пусть задан класс CDataInit, который содержит объявление статических членов с именами a, b, c, d.

public class CDataInit
{
    static int a, b, c, d;

    // инициализация с помощью статического блока
    static
    {
        a = InitMethod("a = ");
        b = InitMethod("b = ");
        c = InitMethod("c = ");
        d = InitMethod("d = ");
    }

    static int InitMethod(String s)
    {
        System.out.println(s + "100");
        return 100;
    }

    public static void main(String[] args)
    {
        // создание объекта - вызывается статический блок
        CDataInit obj = new CDataInit();
        CDataInit obj2 = new CDataInit(); // второй раз статический блок не вызывается
    }
}

В результате выполнения этого кода, будет выведен результат:

a = 100
b = 100
c = 100
d = 100

Как видно, в функции main() создается два объекта, а инициализированные данные выводятся только один раз. Это подтверждает правило, которое гласит: статические члены данных инициализируются в классе только один раз.

Если в функции main() вместо строки

CDataInit obj = new CDataInit();

ввести код обращения к статической переменной, например

CDataInit.a = 25;

то также будет вызван статический блок инициализации, но только один раз.

7. Инициализация массивов в классе. Как в классе инициализировать массив значениями?

В языке Java массив в классе может быть инициализирован одним из двух способов:

  • непосредственным присваиванием значений массива. В этом случае в фигурных скобках { } задается набор значений, которые присваиваются массиву;
  • присваиванием ссылки на другой массив. В этом случае присваивается ссылка на другой массив с помощью оператора присваивания ‘=’.

8. Пример инициализации одномерных массивов в классе

Объявляется класс CInitArray, в котором объявляются массивы a, x и ссылки на них с именами b, y.

public class CInitArray
{
    // инициализация массива в классе
    // вариант 1 - непосредственная инициализация значениями
    int[] a = { 1, 2, 4, 9, -8, 13, 7 }; // в массиве 7 элементов
    double x[] = { -1.33, 2.905, 1.308, 10.301, 8 }; // в массиве 5 элементов

    // вариант 2 - присваивание ссылки
    int[] b = a; // массив b ссылается на одно и то же место что и массив a
    double[] y = x; // массив y ссылается на x

    public static void main(String[] args)
    {
        CInitArray M = new CInitArray();
        int len;

        // проверка длины каждого из массивов
        len = M.a.length; // len = 7
        len = M.x.length; // len = 5

        // проверка конкретных значений массивов
        int d;
        double f;

        d = M.a[3]; // d = 9
        f = M.x[2]; // f = 1.308

        d = M.b[3]; // d = 9
        len = M.b.length; // len = 7

        f = M.y[0]; // f = -1.33
        len = M.y.length; // len = 5

        // изменение в ячейке массива a приводит к изменению в ячейке массива b и наоборот
        M.a[2] = 100;
        d = M.b[2]; // d = 100
        M.b[0] = -11;
        d = M.a[0]; // d = -11

        // так же, изменение в ячейке массива x приводит к изменению в ячейке массива y, и наоборот
        M.x[3] = 1.75;
        f = M.y[3]; // f = 1.75
        M.y[1] = -3.22;
        f = M.x[1]; // f = -3.22
    }
}

Массивы a, x инициализируются начальными значениями с использованием фигурных скобок. После этого длина массивов есть неизменной.

Массивы b и y класса инициализируются значениями, которые есть в массивах a, x. Вернее, массивы b и y ссылаются на ячейки массивов a, x.

В функции main() тестируется длина каждого массива и значения элементов массива. Длину каждого массива можно определить с помощью свойства length.

9. Пример инициализации двумерного массива в классе

Инициализация двумерного массива осуществляется точно также как и одномерного.

public class CInitArray
{
    // инициализация двумерного массива в классе
    // вариант 1 - непосредственная инициализация значениями
    // объявляется двумерный массив aa размером 4*3
    int[][] aa =
    {
        { 1,  2,  5 },
        { 3,  8,  9 },
        { 4, 11, -7 },
        { 2,  2,  0 }
    };

    // вариант 2 - присваивание ссылки
    int[][] bb = aa; // bb ссылается на aa

    public static void main(String[] args)
    {
        CInitArray M = new CInitArray();
        int len, d;

        // проверка длин массивов
        len = M.aa.length; // len = 4 - количество строк
        len = M.aa[0].length; // len = 3 - количество столбиков в строке с индексом 0

        // проверка значений
        d = M.aa[0][2]; // d = 5

        // изменение в ячейке массива a приводит к изменению в ячейке массива b, и наоборот
        M.aa[0][2] = 13;
        d = M.bb[0][2]; // d = 13
        M.bb[1][0] = 25;
        d = M.aa[1][0]; // d = 25
    }
}


Связанные темы