W7. Инкапсуляция, конструкторы, сеттеры и геттеры, поля и методы класса, передача параметров

Автор

Eugene Zouev, Munir Makhmutov

Дата публикации

14 октября 2025 г.

Quiz | Flashcards

1. Краткое содержание

1.1 Базовые принципы ООП (OOP)

Object-Oriented Programming опирается на объекты с данными (fields / атрибуты) и кодом (methods). Три столпа — Encapsulation, Inheritance, Polymorphism. Здесь в основном encapsulation и базовая работа с объектами в Java.

1.2 Инкапсуляция и сокрытие информации
1.2.1 Encapsulation

Encapsulation — объединение состояния объекта и методов, работающих с ним, в одном class; цель — защитить внутреннее состояние от неконтролируемых изменений снаружи. Внешний мир пользуется публичным интерфейсом (как руль и педали у автомобиля), не влезая в «двигатель».

1.2.2 Information hiding

Это принцип, который делает инкапсуляцию работающей в языке: проектировщик класса явно помечает, какие поля и методы public (доступны другим частям программы — «клиентам»), а какие private (внутренние детали). Компилятор Java затем принудительно ограничивает доступ так, что клиенты могут пользоваться только публичной поверхностью.

1.2.3 Access modifiers в Java
  • public — откуда угодно.
  • private — только внутри класса; основа сильной инкапсуляции.
  • protected — пакет + наследники в других пакетах.
  • package-private (без модификатора) — только классы того же пакета.
1.3 Контролируемый доступ: getters и setters

Для private полей используют публичные getters и setters:

  • Getter — читает значение (по конвенции getAge()).
  • Setter — меняет значение (setAge(int newAge)); сюда помещают проверки, чтобы объект оставался в допустимом состоянии (например, отрицательный возраст).
1.4 Создание объектов: constructors

Constructor вызывается при new и задаёт начальное состояние.

1.4.1 Свойства конструкторов
  • Имя совпадает с классом.
  • Нет возвращаемого типа (даже не void).
  • Задаёт начальные значения полей.
  • Если конструкторов нет, компилятор добавит default constructor без параметров с обнулением полей.
1.4.2 Несколько конструкторов (overloading)

Разные списки параметров — constructor overloading. Конструктор без аргументов — default constructor.

1.4.3 Вызов this()

Один конструктор может вызвать другой в том же классе первой строкой: this(...).

1.4.4 Inline initialization

Поля можно инициализировать прямо в объявлении; это выполняется по порядку объявления до тела конструктора.

1.5 Передача данных в методы
1.5.1 Formal vs. actual parameters
  • Formal parameters — параметры в сигнатуре метода.
  • Actual parameters (arguments) — значения при вызове.
1.5.2 Pass-by-value и pass-by-reference (концепции)
  • Pass-by-value: в метод копируется значение; изменения формального параметра не отражаются на исходной переменной снаружи.
  • Pass-by-reference: передаётся ссылка на данные; изменения внутри метода видны снаружи.
1.5.3 Передача параметров в Java

Java всегда pass-by-value. Но:

  • Для primitives копируется само число/символ — оригинал не меняется.
  • Для reference types копируется reference; копия указывает на тот же объект в heap, поэтому содержимое объекта можно менять, а вот переназначить внешнюю ссылку на другой объект метод не может.
1.6 Class members vs. instance members
1.6.1 Instance members

Поля и методы по умолчанию принадлежат экземпляру: у каждого объекта своя копия (Person A и Person B — разные name).

1.6.2 Class members (static)

Static field — одна общая переменная на класс (счётчик созданных объектов и т.п.). Static method вызывается через имя класса (Math.abs()), не имеет this, не обращается к полям экземпляра напрямую.

1.7 Ключевые слова и main
1.7.1 this

Ссылка на текущий экземпляр: разрешение затенения имён, вызов другого конструктора через this(...).

1.7.2 null

Пустая ссылка; разыменование даёт NullPointerException.

1.7.3 Метод main

public static void main(String[] args) — точка входа JVM: public и static, чтобы JVM вызвала без создания объекта; args — аргументы командной строки.


2. Определения

  • Encapsulation: данные и методы в классе + ограничение доступа к внутренностям.
  • Access modifier: public, private, protected, модификатор по умолчанию.
  • Getter: публичное чтение private поля.
  • Setter: публичная запись с возможной валидацией.
  • Constructor: создание и инициализация экземпляра.
  • Constructor overloading: несколько конструкторов с разными параметрами.
  • Pass-by-value: в метод передаётся копия значения.
  • Pass-by-reference: передаётся ссылка на данные (в Java для объектов по-прежнему pass-by-value ссылки).
  • Static field: общее поле класса.
  • Static method: метод класса без привязки к экземпляру.
  • this: ссылка на текущий объект.
  • null: «ни на что не указывает».
  • main method: точка входа приложения.

3. Примеры

3.1. Класс Calculator (Лаба 7, Задание 1)

Класс-калькулятор: main читает из командной строки три аргумента — число, оператор (+, -, *, /), число. Обработайте деление на ноль.

Нажмите, чтобы увидеть решение
public class Calculator {

    // Method for addition.
    public double add(double a, double b) {
        return a + b;
    }

    // Method for subtraction.
    public double subtract(double a, double b) {
        return a - b;
    }

    // Method for multiplication.
    public double multiply(double a, double b) {
        return a * b;
    }

    // Method for division with error handling.
    public double divide(double a, double b) {
        if (b == 0) {
            System.out.println("Error: Division by zero.");
            return -1.0; // Return -1 as specified on error.
        }
        return a / b;
    }

    public static void main(String[] args) {
        // Check if exactly three command-line arguments are provided.
        if (args.length != 3) {
            System.out.println("Usage: java Calculator <number1> <operator> <number2>");
            return;
        }

        // Create an instance of the Calculator class.
        Calculator calc = new Calculator();
        
        // Parse the string arguments into numbers.
        double num1 = Double.parseDouble(args[0]);
        String operator = args[1];
        double num2 = Double.parseDouble(args[2]);
        
        double result = 0;
        
        // Use a switch statement to perform the correct operation.
        switch (operator) {
            case "+":
                result = calc.add(num1, num2);
                break;
            case "-":
                result = calc.subtract(num1, num2);
                break;
            case "*":
                result = calc.multiply(num1, num2);
                break;
            case "/":
                result = calc.divide(num1, num2);
                break;
            default:
                System.out.println("Error: Invalid operator. Use +, -, *, or /.");
                return;
        }
        
        // Print the result.
        System.out.println("Result: " + result);
    }
}
3.2. Классы Book и Author (Лаба 7, Задание 2)

Два класса Book и Author, третий Library с массивом книг, обновлением и выводом. Используйте инкапсуляцию.

Нажмите, чтобы увидеть решение
// Author.java
class Author {
    private String name;
    private String email;
    private char gender;

    public Author(String name, String email, char gender) {
        this.name = name;
        this.email = email;
        this.gender = gender;
    }
    
    // Getters
    public String getName() { return name; }
    public String getEmail() { return email; }
    public char getGender() { return gender; }
    
    @Override
    public String toString() {
        return "Author[name=" + name + ", email=" + email + ", gender=" + gender + "]";
    }
}

// Book.java
class Book {
    private String name;
    private Author author;
    private double price;
    private int qty = 0;
    
    public Book(String name, Author author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }
    
    public Book(String name, Author author, double price, int qty) {
        this.name = name;
        this.author = author;
        this.price = price;
        this.qty = qty;
    }
    
    // Getters and Setters
    public String getName() { return name; }
    public Author getAuthor() { return author; }
    public double getPrice() { return price; }
    public int getQty() { return qty; }
    public void setPrice(double price) { this.price = price; }
    public void setQty(int qty) { this.qty = qty; }
    
    @Override
    public String toString() {
        // Reuse Author's toString() method.
        return "Book[name=" + name + ", " + author.toString() + ", price=" + price + ", qty=" + qty + "]";
    }
}

// Library.java
public class Library {
    public static void main(String[] args) {
        // Create some Author objects.
        Author author1 = new Author("John Doe", "john.doe@example.com", 'm');
        Author author2 = new Author("Jane Smith", "jane.smith@example.com", 'f');
        
        // Create an array to hold Book objects.
        Book[] books = new Book[5];
        
        // Create Book objects and add them to the array.
        books[0] = new Book("Java for Beginners", author1, 29.99, 10);
        books[1] = new Book("Advanced Java", author1, 49.99, 5);
        books[2] = new Book("Python Basics", author2, 25.00, 15);
        
        System.out.println("--- Initial Library Inventory ---");
        for (Book book : books) {
            if (book != null) {
                System.out.println(book.toString());
            }
        }
        
        // Update a book's price and quantity.
        System.out.println("\n...Updating 'Python Basics' price and quantity...");
        books[2].setPrice(27.50);
        books[2].setQty(12);
        
        System.out.println("\n--- Updated Library Inventory ---");
        for (Book book : books) {
            if (book != null) {
                System.out.println(book.toString());
            }
        }
    }
}
3.3. Класс Time и цепочка вызовов (Лаба 7, Задание 3)

Класс Time с временем суток; два экземпляра и разница между ними; метод сдвига на одну секунду с возвратом this для method chaining.

Нажмите, чтобы увидеть решение
// Time.java
class Time {
    private int hours;
    private int minutes;
    private int seconds;

    public Time(int hours, int minutes, int seconds) {
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
    }
    
    // Method to advance time by one second.
    public Time inc() {
        seconds++;
        if (seconds >= 60) {
            seconds = 0;
            minutes++;
            if (minutes >= 60) {
                minutes = 0;
                hours++;
                if (hours >= 24) {
                    hours = 0;
                }
            }
        }
        // Return 'this' to allow for method chaining.
        return this;
    }
    
    // Convert to total seconds for easy difference calculation.
    private int toTotalSeconds() {
        return hours * 3600 + minutes * 60 + seconds;
    }

    // Static method to find the difference.
    public static Time difference(Time t1, Time t2) {
        int diffInSeconds = Math.abs(t1.toTotalSeconds() - t2.toTotalSeconds());
        int h = diffInSeconds / 3600;
        int m = (diffInSeconds % 3600) / 60;
        int s = diffInSeconds % 60;
        return new Time(h, m, s);
    }
    
    @Override
    public String toString() {
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }
}

// TimeCreator.java
public class TimeCreator {
    public static void main(String[] args) {
        // Create 2 instances of Time.
        Time t1 = new Time(14, 20, 58);
        Time t2 = new Time(16, 10, 0);
        
        System.out.println("Time 1: " + t1);
        System.out.println("Time 2: " + t2);
        
        // Calculate the difference.
        Time diff = Time.difference(t1, t2);
        System.out.println("Difference: " + diff);

        // Demonstrate chaining.
        System.out.println("\nAdvancing Time 1 by 3 seconds:");
        System.out.println("Original: " + t1);
        t1.inc().inc().inc(); // Chaining the inc() method.
        System.out.println("New Time: " + t1);
    }
}