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

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


Зміст



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
    }
}


Зв’язані теми