☕ Java

Die while- und do-while-Schleife in Java 17: Eine ausführliche Anleitung

ООП в Java: классы, объекты, наследование и полиморфизм

Объектно-ориентированное программирование (ООП) — это подход к написанию кода, при котором программа моделирует реальный мир через объекты. Вместо набора инструкций — объекты с данными и поведением. Java спроектирована вокруг ООП.

Класс и объект: чертёж и дом

Класс — архитектурный чертёж. Описывает как выглядит и ведёт себя объект.
Объект — конкретный дом, построенный по этому чертежу.

По одному чертежу строят много домов — каждый независимый. Один класс → много объектов.

// КЛАСС — шаблон
class Car {
    // Поля (атрибуты, данные)
    String brand;
    String model;
    int year;
    double price;
    boolean isRunning;
    
    // Методы (поведение)
    void start() {
        if (!isRunning) {
            isRunning = true;
            System.out.println(brand + " " + model + " заведён!");
        } else {
            System.out.println("Двигатель уже работает.");
        }
    }
    
    void stop() {
        if (isRunning) {
            isRunning = false;
            System.out.println(brand + " " + model + " остановлен.");
        }
    }
    
    void honk() { System.out.println(brand + ": Бип-бип!"); }
    
    void describe() {
        System.out.printf("%d %s %s, %.0f₽%n", year, brand, model, price);
    }
}

public class ClassDemo {
    public static void main(String[] args) {
        
        // Создаём ОБЪЕКТЫ с помощью new
        Car lada = new Car();
        lada.brand = "ВАЗ";
        lada.model = "Лада Гранта";
        lada.year  = 2022;
        lada.price = 850_000;
        
        Car bmw = new Car();
        bmw.brand = "BMW";
        bmw.model = "X5";
        bmw.year  = 2023;
        bmw.price = 7_500_000;
        
        // Каждый объект независим!
        lada.describe();
        bmw.describe();
        
        lada.start(); // ВАЗ Лада Гранта заведён!
        lada.honk();
        lada.start(); // Двигатель уже работает.
        lada.stop();
        
        bmw.start();
        bmw.honk();   // BMW: Бип-бип!
    }
}

Конструкторы: правильная инициализация

class Point {
    double x, y;
    
    // Конструктор по умолчанию (начало координат)
    Point() { x=0; y=0; }
    
    // С параметрами
    Point(double x, double y) {
        this.x = x;  // this.x — поле; x — параметр конструктора
        this.y = y;
    }
    
    // Конструктор копирования
    Point(Point other) { this.x=other.x; this.y=other.y; }
    
    double distanceTo(Point other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        return Math.sqrt(dx*dx + dy*dy);
    }
    
    @Override
    public String toString() {
        return String.format("(%.1f, %.1f)", x, y);
    }
}

Point origin = new Point();              // (0.0, 0.0)
Point p1 = new Point(3.0, 4.0);         // (3.0, 4.0)
Point p2 = new Point(0.0, 0.0);
Point p1copy = new Point(p1);            // Копия p1

System.out.println(p1);                  // (3.0, 4.0)
System.out.println(p1.distanceTo(p2));   // 5.0 (теорема Пифагора: 3²+4²=5²)

p1copy.x = 10.0; // Изменяем копию — оригинал не трогаем
System.out.println(p1);     // (3.0, 4.0) — оригинал не изменился
System.out.println(p1copy); // (10.0, 4.0) — копия изменена

Инкапсуляция: скрываем детали

Аналогия: Телевизор. Вы нажимаете кнопки пульта (публичный интерфейс) — не зная что происходит внутри (скрытая реализация). Именно так работает инкапсуляция.

class Student {
    private String name;    // private — только внутри класса
    private int grade;      // оценка 1-5
    private double gpa;
    
    // Конструктор с валидацией
    public Student(String name, int grade) {
        this.name = name;
        setGrade(grade); // используем setter с проверкой
    }
    
    // Getter — только читаем
    public String getName()  { return name; }
    public int    getGrade() { return grade; }
    public double getGpa()   { return gpa; }
    
    // Setter с валидацией — защита от некорректных данных
    public void setGrade(int grade) {
        if (grade < 1 || grade > 5) {
            System.out.println("Ошибка: оценка должна быть от 1 до 5!");
            return;
        }
        this.grade = grade;
        this.gpa = (grade - 1) * 1.25; // Вычисляем GPA автоматически
    }
    
    public void printInfo() {
        System.out.printf("Студент: %s, оценка: %d, GPA: %.2f%n", name, grade, gpa);
    }
}

Student s = new Student("Иван", 4);
s.printInfo(); // Студент: Иван, оценка: 4, GPA: 3.75

s.setGrade(5); // Обновляем через setter
s.printInfo(); // Студент: Иван, оценка: 5, GPA: 5.00

s.setGrade(7); // Ошибка: оценка должна быть от 1 до 5!

// s.grade = 10; // ОШИБКА КОМПИЛЯЦИИ: grade has private access

Наследование

// Базовый класс
class Animal {
    protected String name; protected int age;
    
    Animal(String name, int age) { this.name=name; this.age=age; }
    
    void breathe() { System.out.println(name + " дышит"); }
    void eat(String food) { System.out.println(name + " ест " + food); }
    void sleep() { System.out.println(name + " спит"); }
    String info() { return name + " (" + age + " лет)"; }
}

// Dog наследует Animal и добавляет своё
class Dog extends Animal {
    private String breed;
    private boolean vaccinated;
    
    Dog(String name, int age, String breed) {
        super(name, age); // ПЕРВЫМ вызываем конструктор родителя!
        this.breed = breed;
        this.vaccinated = false;
    }
    
    // Специфичные методы Dog
    void bark()  { System.out.println(name + " (" + breed + "): ГАВ-ГАВ!"); }
    void fetch(String item) { System.out.println(name + " принёс " + item + "!"); }
    void vaccinate() { vaccinated=true; System.out.println(name + " привит."); }
    
    @Override // Переопределяем метод родителя
    String info() { return super.info() + ", порода: " + breed + ", привит: " + vaccinated; }
}

class Cat extends Animal {
    private boolean indoor;
    Cat(String name, int age, boolean indoor) { super(name,age); this.indoor=indoor; }
    void meow() { System.out.println(name + ": МЯУ~"); }
    void purr()  { System.out.println(name + " мурлычет ♪"); }
    @Override String info() { return super.info()+(indoor?", домашняя":", уличная"); }
}

Dog rex = new Dog("Рекс", 3, "Немецкая овчарка");
Cat mur = new Cat("Мурка", 5, true);

// Методы унаследованные от Animal
rex.breathe(); rex.eat("мясо"); rex.sleep();

// Специфичные методы
rex.bark(); rex.fetch("мячик"); rex.vaccinate();
System.out.println(rex.info());

mur.meow(); mur.purr();
System.out.println(mur.info());

// instanceof — проверка типа
System.out.println(rex instanceof Animal); // true
System.out.println(rex instanceof Dog);    // true
System.out.println(rex instanceof Cat);    // false

Полиморфизм: один вызов — разное поведение

abstract class Shape {
    protected String color;
    Shape(String c) { color=c; }
    
    abstract double area();       // Каждый подкласс ОБЯЗАН реализовать
    abstract double perimeter();
    
    void describe() {  // Общий метод — вызывает переопределённые методы
        System.out.printf("[%s] площадь=%.2f, периметр=%.2f%n",
                          color, area(), perimeter());
    }
}

class Circle extends Shape {
    double r;
    Circle(String c, double r) { super(c); this.r=r; }
    @Override double area()      { return Math.PI*r*r; }
    @Override double perimeter() { return 2*Math.PI*r; }
}

class Rectangle extends Shape {
    double w,h;
    Rectangle(String c, double w, double h) { super(c); this.w=w; this.h=h; }
    @Override double area()      { return w*h; }
    @Override double perimeter() { return 2*(w+h); }
}

class Square extends Shape {
    double side;
    Square(String c, double s) { super(c); side=s; }
    @Override double area()      { return side*side; }
    @Override double perimeter() { return 4*side; }
}

// ПОЛИМОРФИЗМ: один и тот же вызов — разное поведение у разных объектов
Shape[] shapes = {
    new Circle("красный",5), new Rectangle("синий",4,6),
    new Square("зелёный",3), new Circle("жёлтый",2)
};
double totalArea = 0;
for (Shape s : shapes) {
    s.describe();        // У каждой фигуры своя реализация area() и perimeter()
    totalArea += s.area();
}
System.out.printf("Суммарная площадь: %.2f%n", totalArea);

Интерфейсы

interface Drawable {
    void draw();                           // abstract по умолчанию
    default void print() {                 // default — есть реализация
        System.out.println("Рисую: " + getClass().getSimpleName());
    }
    static void info() {                   // static метод интерфейса
        System.out.println("Drawable interface v1.0");
    }
}

interface Saveable { void save(String file); }
interface Resizable { void resize(double factor); double getSize(); }

// Класс может реализовать несколько интерфейсов!
class SmartShape implements Drawable, Saveable, Resizable {
    private double size; private String color;
    SmartShape(double s, String c) { size=s; color=c; }
    
    @Override public void draw()   { System.out.printf("%s фигура размера %.1f%n",color,size); }
    @Override public void save(String f) { System.out.println("Сохраняю в "+f); }
    @Override public void resize(double f) { size*=f; System.out.printf("Новый размер: %.1f%n",size); }
    @Override public double getSize() { return size; }
}

SmartShape ss = new SmartShape(5.0, "Синяя");
ss.draw();
ss.print();    // default метод
ss.resize(2.0);
ss.save("shape.dat");
Drawable.info(); // static метод

Итого: что мы узнали

  • ✅ Класс = шаблон (чертёж), Объект = экземпляр (конкретный дом)
  • ✅ Поля хранят данные, методы описывают поведение объекта
  • ✅ Конструктор: инициализирует объект при new; this — текущий объект
  • ✅ Инкапсуляция: private поля + публичные методы (геттеры/сеттеры)
  • ✅ Наследование (extends): подкласс получает всё от родителя
  • ✅ super — обращение к родителю; @Override — переопределение метода
  • ✅ Полиморфизм: один вызов — разное поведение в разных классах
  • ✅ abstract класс: нельзя создать объект; содержит абстрактные методы
  • ✅ Интерфейс: контракт поведения; класс реализует через implements
  • ✅ Класс наследует один класс (extends), но реализует много интерфейсов (implements)