Ініціалізація змінних у методах класу. Ініціалізація полів (членів даних) класу. Способи ініціалізації членів даних класу

Ініціалізація змінних у методах класу. Ініціалізація полів (членів даних) класу. Способи ініціалізації членів даних класу

Дана тема демонструє способи ініціалізації внутрішніх членів даних класу у мові програмування Java.


Зміст


1. Поняття ініціалізації змінних у методах в Java

Ініціалізація змінної означає явне (або неявне) встановлення деякого значення змінній.

У мові програмування Java змінні, що оголошені в методі, обов’язково мають бути ініціалізовані перед їх використанням.

Якщо у тілі деякого методу класу, спробувати використати оголошену, але не ініціалізовану змінну, то компілятор видасть помилку.

Наприклад. У нижченаведеному фрагменті коду відбувається спроба використати змінну t, яка оголошена але не ініціалізована

static void SomeMethod()
{
    int t;
    int x;

    x = 6;
    x = x + t + 2; // тут помилка: змінна t не ініціалізована
}

У цьому випадку видається повідомлення про помилку:

The local variable t may not have been initialized

Щоб виправити ситуацію, потрібно змінній t присвоїти якесь значення перед її використанням.

2. Які існують способи ініціалізації членів даних класу?

В Java можна ініціалізувати змінну, якщо вона є членом даних класу. Існує чотири способи ініціалізації членів даних класу:

  • ініціалізація за замовчуванням (неявна ініціалізація);
  • явна ініціалізація початковими значеннями (константними значеннями);
  • явна ініціалізація методами класу;
  • ініціалізація з допомогою конструкторів класів.

 



3. Ініціалізація полів даних класу. Що таке ініціалізація полів даних класу за замовчуванням?

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

Тобто, якщо є клас в якому оголошені внутрішні змінні (поля класу)

class SomeClass
{
    int d;
    double x;

    // ...
}

то ці змінні (d, x) будуть ініціалізовані значенням за замовчуванням. У вищенаведеном коді змінним за замовчуванням буде присвоєно наступні значення

d = 0.0
x = 0

Немає значення, який ідентифікатор доступу використовується для змінної (private, protected, public).

4. Які значення за замовчуванням присвоюються полям класу для різних типів?

При оголошенні в класі змінної, цій змінній присвоюються значення за замовчуванням. Нижче наведено значення за замовчуванням, які присвоюються змінним різних типів

int      => 0
boolean  => false
double   => 0.0
float    => 0.0
char     => ' ' - нуль-символ
long     => 0
byte     => 0

Символьній змінній типу char присвоюється нуль-символ, який відображається у вигляді символу “пробіл”.

5. Яким значенням ініціалізується змінна-посилання на об’єкт класу?

Якщо у класі оголошується змінна-посилання на об’єкт деякого класу, то за замовчуванням, значення цього посилання рівне null.

Нижченаведений фрагмент коду демонструє це.

// деякий клас
public class InnerClass
{
    // ...
}

// клас, в якому оголошено об'єкт класу InnerClass
public class MyClass
{
    // ...

    public static InnerClass obj; // obj = null; - за замовчуванням

    // ...
}

У вищенаведеному прикладі змінна obj є посиланням (reference) на клас InnerClass. Іншими словами obj це об’єкт класу InnerClass. Оскільки, пам’ять для obj ще не виділена, то за замовчуванням значення obj = null.

6. Явна ініціалізація. Яким чином здійснюється явна ініціалізація членів даних класу початковими значеннями?

Явна ініціалізація означає задавання початкового (потрібного) значення змінній при її оголошенні в класі.

Наприклад. У класі MyClass реалізована ініціалізація початковими значеннями змінних різних типів.

public class CTrain01
{
    // явна ініціалізація початкових значень змінних
    int d = 25; // явна ініціалізація змінної d типу int значенням 25
    float y = 3.885f;
    public double x = -129.48;
    boolean b = true;
    char c = 'Z';
    long l = 0xF3309FA;

    // ...
}

У мовах C/C++ таке не допускається.

7. Яким чином здійснюється явна ініціалізація членів даних класу, що є змінними-посиланнями на клас

Якщо членом даних класу є змінна-посилання на деякий клас (об’єкт класу), то вона ініціалізується стандартним способом з допомогою оператора new:

class InnerClass
{
    // ...
}

class MyClass
{
    // ...

    // явна ініціалізація змінної obj в класі MyClass
    InnerClass obj = new InnerClass();

    // ...
}

У класі MyClass змінна-посилання obj перед її використанням обов’язково має бути ініціалізована оператором new. Якщо спробувати використати неініціалізовану змінну, яка є посиланням на клас, виникне критична ситуація (виключення).

8. Явна ініціалізація з допомогою виклику методів. Яким чином ініціалізується значення члена даних класу з допомогою виклику методу?

При оголошенні, члени даних класу можуть бути ініціалізовані викликом деякого методу.

Наприклад. Нехай задано клас CRadius. У класі CRadius ініціалізуються члени даних len, area, volume з допомогою виклику методів Length(), Area(), Volume(). Ці методи обчислюють відповідно довжину кола, площу круга та об’єм кулі радіусу r, що є вхідним параметром.

public class CRadius
{
    // приховані змінні
    private double Pi = 3.1415;
    private double radius=1;

    // загальнодоступні змінні
    public double len = Length(radius); // ініціалізація змінної len методом Length()
    public double area = Area(radius); // ініціалізація змінної area методом Area()
    public double volume = Volume(radius); // ініціалізація змінної volume методом Volume()

    // методи обчислення
    double Length(double r) { return 2*Pi*r; }
    double Area(double r) { return Pi*r*r; }
    double Volume(double r) { return 4.0/3.0*Pi*r*r*r; }

    public static void main(String[] args)
    {
        // демонстрація ініціалізації методами класу CRadius
        CRadius r1 = new CRadius(); // явна ініціалізація членів даних об'єкту r1
        double l, a, v;

        l = r1.len; // l = 6.283;
        a = r1.area; // a =   3.1415
        v = r1.volume; // v = 4.1886666666
    }
}

9. Який порядок ініціалізації при оголошенні змінних? Яке значення має порядок ініціалізації при оголошенні змінних? Приклади

У класі змінні ініціалізуються в першу чергу. Ініціалізація змінних відбувається навіть перед викликом конструктору класу. Порядок ініціалізації змінних визначається порядком їх оголошення у класі (див. приклад 1). Після ініціалізації змінних викликається конструктор. При цьому, оголошення та ініціалізація змінних можуть бути реалізовані у будь-якому місці класу (див. приклад 2).

Як видно з програмного коду у пункті 8, змінні оголошуються у строго визначеній послідовності, в якій значення ініціалізуючих змінних та методів (справа від операції присвоєння) було визначене на момент ініціалізації.

Приклад 1. Нехай задано клас CInitOrderClass, у якому значення наступного члена даних ініціалізується значенням попереднього члена даних або методу.

// у класі демонструється правильний порядок ініціалізації
public class CInitOrderClass
{
    int t1 = 5;
    int t2 = SomeMethod(); // t2 = 100;
    int t3 = t2; // t3 = 100
    int t4 = t1 + t3; // t4 = 5 + 100 = 105
    int t5 = SomeMethod() + t4; // t5 = 205

    // метод, що використовується при ініціалізації
    int SomeMethod()
    {
        return 100;
    }

    public static void main(String[] args)
    {
        // Демонстрація використання об'єкту класу CInitOrderClass
        CInitOrderClass obj = new CInitOrderClass();
        int d;

        d = obj.t1; // d = 5
        d = obj.t2; // d = 100
        d = obj.t3; // d = 100
        d = obj.t4; // d = 105
        d = obj.t5; // d = 205
    }
}

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

public class CInitOrderClass
{
    int t4 = t1 + t3; // t4 = ??? - тут помилка, змінні t1, t3 ще не оголошені
    int t1 = 5;
    int t2 = SomeMethod(); // t2 = 100;
    int t3 = t2; // t3 = 100
    int t5 = SomeMethod() + t4; // t5 = 205

    // ...
}

то виникне помилка компіляції

Cannot reference a field before it is defined

Це є логічним, оскільки перегляд оголошень змінних відбувається зверху-донизу (з початку до кінця). На момент оголошення змінної t4, змінні t1 та t3 які беруть участь в ініціалізації ще не оголошені. Це є причиною виникнення помилки.

Це не стосується методу класу SomeMethod(), який може використовуватись при ініціалізації у будь-якому місці класу.

Приклад 2. Даний приклад демонструє правило, в якому будь-яка внутрішня змінна класу (член даних класу) ініціалізується першою, навіть перед викликом конструктора.

Нехай дано реалізацію класу COrderInit, в якому ініціалізуються три змінні a, b, c з допомогою методу InitMethod() та з допомогою конструктора COrderInit().

// у класі демонструється порядок ініціалізації
public class COrderInit
{
    int a = InitMethod("a = "); // ініціалізація змінної a з допомогою методу

    // ініціалізація змінних конструктором
    COrderInit()
    {
        a = b = c = 0;
        System.out.println("Constructor COrderInit().");
    }

    int c = InitMethod("c = "); //ініціалізація змінної c

    // метод, що ініціалізує змінні
    int InitMethod(String s)
    {
        System.out.println(s + "InitMethod().");
        return 100;
    }

    int b = InitMethod("b = "); // ініціалізація змінної b

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

Як видно з вищенаведеного коду, клас містить функцію main(), в якій створюється об’єкт класу COrderInit. Метод класу InitMethod() отримує вхідним параметром рядок s. Цей рядок виводить рядок ініціалізації з іменем відповідної змінної.

У результаті виконання такого коду буде виведено наступний результат:

a = InitMethod().
c = InitMethod().
b = InitMethod().
Constructor COrderInit().

Результат показує, що першою відбувається ініціалізація змінних a, c, b. Порядок ініціалізації змінних визначається порядком їх оголошення в класі. Після цього відбувається виклик конструктора.

10. Яким чином здійснюється ініціалізація з допомогою конструктора?

Ініціалізація членів даних класу з допомогою конструктора більш детально описується в темі:

11. Яким чином можна ініціалізувати члени даних класу з допомогою секції ініціалізації { }? Приклад

Члени даних класу можна ініціалізувати в одній секції, як показано у прикладі.

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

    // ініціалізація з допомогою секції ініціалізації { }
    {
        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
    }
}

12. Що виконується першим: секція ініціалізації чи конструктор класу?

Першою виконується секція ініціалізації а потім конструктор.


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