ООП — основы

Быстрая навигация


Класс и объект

public class Dog {
    // Поля (состояние)
    String name;
    int age;

    // Метод (поведение)
    void bark() {
        System.out.println(name + " says: Woof!");
    }
}

// Создание объекта
Dog d = new Dog();
d.name = "Rex";
d.age = 3;
d.bark();            // Rex says: Woof!

Конструктор

public class Dog {
    String name;
    int age;

    // Конструктор — вызывается при new
    public Dog(String name, int age) {
        this.name = name;   // this — ссылка на текущий объект
        this.age = age;
    }

    // Перегрузка конструктора
    public Dog(String name) {
        this(name, 0);      // вызов другого конструктора
    }
}

Dog d1 = new Dog("Rex", 3);
Dog d2 = new Dog("Buddy");  // age = 0

Конструктор по умолчанию — если не написать ни одного, Java сделает пустой Dog() {} сам. Если написал хоть один — дефолтный исчезает.


Модификаторы доступа

public class BankAccount {
    private double balance;    // снаружи не видно

    public double getBalance() {
        return balance;
    }
    public void deposit(double sum) {
        if (sum > 0) balance += sum;
    }
}

BankAccount acc = new BankAccount();
// acc.balance = 100;    // ОШИБКА компиляции
acc.deposit(100);        // OK
acc.getBalance();        // OK

static

public class Counter {
    static int count = 0;   // одно на всех, не на объект

    public Counter() {
        count++;
    }

    static void reset() {   // вызывается через класс, не объект
        count = 0;
    }
}

Counter.count;           // 0
new Counter();
new Counter();
Counter.count;           // 2
Counter.reset();
Counter.count;           // 0

Правило: static метод не может обращаться к нестатическим полям.


final

final int MAX = 100;
MAX = 200;               // ОШИБКА — нельзя изменить

final class Locked {}    // нельзя наследовать

class Base {
    final void show() {} // нельзя переопределить в наследнике
}

Наследование (extends)

public class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public void speak() {
        System.out.println(name + " makes a sound");
    }
}

public class Cat extends Animal {
    public Cat(String name) {
        super(name);         // конструктор родителя — обязателен первым
    }

    @Override
    public void speak() {
        System.out.println(name + " says: Meow!");
    }
}

Animal a = new Cat("Whiskers");
a.speak();   // Whiskers says: Meow!

Абстрактный класс

// Нельзя создать объект — только наследовать
public abstract class Shape {
    String color;

    public void setColor(String c) { this.color = c; }

    // Без реализации — наследник ОБЯЗАН написать
    public abstract double area();
}

public class Circle extends Shape {
    double radius;

    public Circle(double radius) { this.radius = radius; }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

Shape s = new Circle(5);
s.area();           // 78.53...
// new Shape();     // ОШИБКА

Интерфейс (interface)

public interface Printable {
    void print();                    // абстрактный по умолчанию

    default void printTwice() {      // default — есть реализация
        print();
        print();
    }
}

public interface Saveable {
    void save();
}

// Можно реализовывать несколько!
public class Document implements Printable, Saveable {
    @Override
    public void print() { System.out.println("Printing..."); }

    @Override
    public void save() { System.out.println("Saving..."); }
}

Интерфейс vs Абстрактный класс:
- Интерфейс: контракты, нет полей состояния, несколько сразу
- Абстракт: поля + реализация, только один родитель


Полиморфизм

Animal[] animals = {new Cat("Kitty"), new Dog("Rex")};

for (Animal a : animals) {
    a.speak();   // каждый говорит по-своему
}
// Проверка типа
Animal a = new Cat("Kitty");

// Старый способ
if (a instanceof Cat) {
    Cat c = (Cat) a;
    c.purr();
}

// Java 16+ — сразу с переменной
if (a instanceof Cat c) {
    c.purr();
}

equals и toString

public class Point {
    int x, y;

    public Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Point)) return false;
        Point p = (Point) o;
        return x == p.x && y == p.y;
    }
}

System.out.println(new Point(1, 2));           // Point(1, 2)
new Point(1, 2).equals(new Point(1, 2));       // true
← Меню