Конструктори. Параметризовані конструктори. Ключове слово this. Збір “сміття”. Метод finalize()

Конструктори. Параметризовані конструктори. Ключове слово this. Збір “сміття”. Метод finalize()


Зміст


1. Що називається конструктором класу? Призначення конструктора

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

Загальна форма оголошення конструктора

ClassName(parameters)
{
    // тіло конструктора
    // ...
}

де

  • ClassName – ім’я конструктора, яке співпадає з іменем класу. Конструктор не повертає значення;
  • parameters – параметри конструктора. Конструктор може бути без параметрів (за замовчуванням).

2. Приклади використання конструкторів класу

Приклад 1. Оголошення та використання класу Month, що містить інформацію про місяць року.

У класі оголошується:

  • внутрішня, прихована (private) змінна класу з іменем month;
  • конструктор без параметрів, який встановлює значення внутрішньої змінної month в 1 (січень);
  • конструктор з одним параметром, що ініціалізує значення змінної month початковим значенням;
  • методи доступу Get(), Set() до внутрішньої змінної month;
  • методи Next() та Prev(), що встановлюють наступний та попередній місяці в році;
  • метод MonthStr(), що повертає назву місяця.
public class Month 
{
    // клас, що описує місяць року
    private int month; // внутрішня змінна (ключове слово private)

    // Оголошення конструкторів класу
    // конструктор без параметрів
    Month()
    {
        month = 1; // місяць "січень" за замовчуванням
    }

    // конструктор з одним параметром
    Month(int mn)
    {
        if ((mn>=1)&&(mn<=12)) // перевірка, чи вірно заданий номер місяця 1..12
            month = mn;
        else
            month = 1;
    }

    // Методи класу
    // методи доступу
    int Get() { return month; } // взяти поточний номер місяця
    void Set(int nmonth)
    {
        // встановити нове значення
        if ((nmonth>=1)&&(nmonth<=12))
            month = nmonth;
    }

    // Додаткові методи класу
    // встановити наступний місяць у році
    int Next()
    {
        month++;
        if (month==13) month = 1;
        return month;
    }

    // встановити попередній місяць у році
    int Prev()
    {
        month--;
        if (month==0) month = 12;
        return month;
    }

    // взяти назву місяця
    String MonthStr()
    {
        String s="";
        if (month==1) s = "Jan";
        if (month==2) s = "Feb";
        if (month==3) s = "Mar";
        if (month==4) s = "Apr";
        if (month==5) s = "May";
        if (month==6) s = "Jun";
        if (month==7) s = "Jul";
        if (month==8) s = "Aug";
        if (month==9) s = "Sep";
        if (month==10) s = "Oct";
        if (month==11) s = "Nov";
        if (month==12) s = "Dec";
        return s;
    }
}

Використання класу в іншій функції:

Month m1 = new Month(); // виклик конструктора без параметрів
int d;
String s;

d = m1.Get(); // d = 1;
d = m1.Prev(); // d = 12
s = m1.MonthStr(); // s = "Dec"

Month m2 = new Month(5); // виклик конструктора з 1 параметром
d = m2.Get(); // d = 5
m2.Next();
s = m2.MonthStr(); // s = "Jun"
m2.Set(9);
s = m2.MonthStr(); // s = "Sep"

Приклад 2. Нехай дано клас MyRect, який описує прямокутник. Для прямокутника задаються такі внутрішні змінні:

  • координати x, y лівого верхнього кута екрану;
  • довжини сторін dx, dy прямокутника.

У класі реалізовано 3 конструктори та 6 методів:

  • конструктор без параметрів;
  • конструктор з 2 параметрами (параметризований конструктор);
  • конструктор з 4 параметрами (параметризований конструктор);
  • методи читання значень внутрішніх змінних GetX(), GetY(), GetDX(), GetDY();
  • метод Set(), що встановлює нові значення внутрішніх змінних;
  • метод Square(), що обчислює площу прямокутника.
public class MyRect 
{
    // внутрішні змінні класу
    private int x, y, dx, dy; // приховані - ключове слово private

    // Конструктори класу
    // конструктор без параметрів
    MyRect()
    {
        x = 0;
        y = 0;
        dx = 1;
        dy = 1;
    }

    // параметризований конструктор з двома параметрами
    MyRect(int dx, int dy)
    {
        this.dx = dx;
        this.dy = dy;
        x = 0;
        y = 0;
    }

    // параметризований конструктор з 4 параметрами
    MyRect(int nx, int ny, int ndx, int ndy)
    {
        x = nx;
        y = ny;
        dx = ndx;
        dy = ndy;
    }

    // Методи класу
    // читання внутрішніх даних класу
    int GetX() { return x; }
    int GetY() { return y; }
    int GetDX() { return dx; }
    int GetDY() { return dy; }

    // запис нових значень у внутрішні дані класу
    void Set(int nx, int ny, int ndx, int ndy)
    {
        x = nx;
        y = ny;
        dx = ndx;
        dy = ndy;
    }

    // метод, що обчислює площу прямокутника
    int Square()
    {
        return (int)(dx*dy);
    }
}

У параметризованому конструкторі з 2 параметрами на вхід поступають внутрішні параметри з іменами dx, dy. Такі самі імена мають внутрішні змінні класу. Щоб доступитись до внутрішніх змінних класу за межами тіла конструктора, використовується ключове слово this:

...
this.dx = dx;
this.dy = dy;
...

Використання класу в іншому програмному коді (наприклад, функції main):

// використання класу
MyRect r1 = new MyRect(); // виклик конструктора без параметрів
int d;

// перевірка
d = r1.GetDX(); // d = 1
r1.Set(5, 6, 2, 3); // виклик методу Set() класу

int s = r1.Square(); // s = 6 - площа прямокутника

// виклик конструктора з 2 параметрами
MyRect r2 = new MyRect(5,4);
d = r2.GetX(); // d = 0
d = r2.GetDY(); // d = 4

// виклик конструктора з 4 параметрами
MyRect r3 = new MyRect(2,3,8,9);
d = r3.GetDY(); // d = 9
d = r3.Square(); // d = 72 - площа, метод Square()

3. Що таке параметризовані конструктори?

Параметризовані конструктори – це конструктори, які отримують параметри.

4. Для чого використовується ключове слово this? Приклад

Ключове слово this використовується для того, щоб отримати в методі посилання на об’єкт, який його викликав. Ключове слово this можна використовувати в тілі будь-якого методу для посилання на поточний об’єкт.

Приклад. Нехай дано клас DWeek, що описує день тижня.

У класі оголошується:

  • внутрішня змінна day;
  • конструктор без параметрів;
  • конструктор з 1 параметром;
  • методи доступу Get() та Set();
  • метод IsDayOff(), що визначає, вихідний день чи ні.
// Клас, що описує день тижня
public class DWeek 
{
    // внутрішня прихована (private) змінна day
    private int day;

    // Конструктори класу
    DWeek() // конструктор без параметрів
    {
        day = 1; // Понеділок
    }

    // конструктор з 1 параметром
    DWeek(int day)
    {
        // доступ до змінної-екземпляру класу day за допомогою ключового слова this
        if ((day>=1)&&(day<=7))
        this.day = day;
    }

    // методи доступу
    int Get() { return day; }

    void Set(int day)
    {
        // доступ до змінної екземпляру: this.day
        if ((day>=1)&&(day<=7))
        this.day = day;
    }

    // метод, що визначає, чи вихідний цей день чи ні
    boolean IsDayOff()
    {
        int d; // внутрішня змінна
        // виклик методу Get() класу з допомогою ключового слова this
        d = this.Get(); // взяти поточний день

        boolean b = true;
        if ((d>=1)&&(d<=5)) b = false;
        return b;
    }
}

У конструкторі з 1 параметром вхідний параметр має таке саме ім’я як і внутрішня змінна класу day. Тому, щоб доступитись до змінної-екземпляра класу day використовується ключове слово this:

// конструктор з 1 параметром
DWeek(int day)
{
    // доступ до змінної-екземпляру класу day за допомогою ключового слова this
    this.day = day;
}

Те саме стосується і методу Set(), в якому ім’я вхідного параметру співпадає з іменем екземпляру класу. У цьому випадку використання ключового слова this є ефективним. Звичайно, при бажанні можна змінити ім’я вхідного параметру.

У методі IsDayOff() для доступу до методу Get() використовується ключове слово this (в демонстраційних цілях).

Використання класу в іншому методі

public static void main(String[] args) 
{
    // використання класу DWeek
    DWeek dw1 = new DWeek(); // виклик конструктора без параметрів
    boolean b;
    int d;

    b = dw1.IsDayOff(); // b = false
    d = dw1.Get(); // d = 1

    DWeek dw2 = new DWeek(7);
    b = dw2.IsDayOff(); // b = true
    dw2.Set(4);
    d = dw2.Get(); // d = 4
    b = dw2.IsDayOff(); // b = false

    System.out.println(d);
}

5. Що означає термін “збір сміття”? Як відбувається “збір сміття”?

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



6. Яке призначення методу finalize() в Java?

У методі finalize() вказуються дії, що мають бути виконані перед знищенням об’єкту. Це дії, які відрізняються від ресурсів Java, наприклад, збереження проміжних даних/результатів, знищення дескриптору файлу тощо.

Якщо метод finalize() визначений у класі, то він викликається перед тим, як повинен бути знищений об’єкт класу “збирачем сміття”. Ця процедура виглядає приблизно так:

  • “збирач сміття” час від часу запускається і перевіряє наявність об’єктів, на які відсутні посилання. Ці об’єкти потрібно видалити;
  • для знайдених об’єктів спочатку викликається метод finalize(), якщо він визначений у класі. У цьому методі виконуються відповідні дії зі звільнення “відмінних від Java” ресурсів;
  • видаляється знайдений об’єкт.

Метод finalize() має такий загальний вигляд:

protected void finalize()
{
    // тіло методу
    // ...
}

Цей метод повинен бути оголошений в класі, наприклад:

class MyClass
{
    // ...

    protected void finalize()
    {
        // ...
    }

    // ...
}

 

7. Яким чином реалізується присвоювання змінним посилань на об’єкти класу?

Якщо оголошено дві змінні (два об’єкти) деякого класу з іменами v1 та v2 і для змінної v1 виділена пам’ять оператором new, то рядок

v2 = v1;

буде означати наступне:

  • змінна v2 містить посилання на об’єкт v1;
  • змінні v2 та v1 посилаються на одну й ту ж область пам’яті. Це означає, що пам’ять для змінної v2 не виділяється. Зміни за посиланням в змінній v1 призведуть до тих самих змін у змінній v2 (і навпаки);
  • ці змінні не зв’язані між собою. Тобто, якщо змінити значення однієї зі змінних, то це не вплине на значення іншої змінної (інша змінна залишиться посилатись на вихідний об’єкт).


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