W7. Инкапсуляция, конструкторы, сеттеры и геттеры, поля и методы класса, передача параметров
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: «ни на что не указывает».mainmethod: точка входа приложения.
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.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);
}
}