Skip to content
IRC-CodingIRC-Coding
OOPОсновыклассобъектинстансатрибутыметодынаследованиеполиморфизминкапсуляцияэкзамен IHK

OOP Основы: класс, объект, инстанс и методы

OOP основы: класс vs объект, атрибуты, методы, наследование, полиморфизм, инкапсуляция для экзамена IHK.

S

schutzgeist

13 min read
OOP Основы: класс, объект, инстанс и методы

Основы ООП: Класс, объект, экземпляр и методы для экзамена IHK

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

Зачем нужно ООП

Представь, что ты собираешь автомобиль. Не станешь же каждый раз заново создавать винты, колёса и детали. Вместо этого используешь готовые, многоразовые компоненты (шины, сиденья, двигатели) с определённой функциональностью, которые работают вместе. Так же функционирует и ООП. Это парадигма программирования, которая собирает программное обеспечение из переиспользуемых, чётко структурированных “блоков” — объектов. Это делает код проще в обслуживании, расширении и понимании.

Главное различие: Класс и Объект (экземпляр)

Это основа. Если ты это поймёшь, остальное логично следует.

Класс (чертёж)

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

Пример: Класс Auto. Чертёж говорит: “Автомобиль имеет атрибуты farbe, anzahlTueren и leistungInPS. Он может выполнять методы bremsen() и beschleunigen().”

Класс существует в коде один раз.

Объект / Экземпляр (конкретная вещь)

Объект — это конкретное воплощение (экземпляр) класса. Он создаётся во время выполнения программы из класса (ключевое слово new в языках типа Java или C#).

Пример: Объект meinGolf — это экземпляр класса Auto. Он имеет конкретные значения атрибутов: farbe = "blau", anzahlTueren = 5, leistungInPS = 150. Объект deinA3 — это другой экземпляр с другими значениями: farbe = "schwarz", anzahlTueren = 3, leistungInPS = 120.

Из одного класса можно создать сколько угодно объектов.

Простая аналогия

  • Класс = чертёж дома (определяет наличие стен, дверей, окон)
  • Объект = реально построенный дом (конкретный адрес, белые стены, дверь из дуба)
// Пример на Java: Класс и объект
public class Auto {
    // Атрибуты (свойства)
    private String farbe;
    private int anzahlTueren;
    private int leistungInPS;
    
    // Конструктор
    public Auto(String farbe, int anzahlTueren, int leistungInPS) {
        this.farbe = farbe;
        this.anzahlTueren = anzahlTueren;
        this.leistungInPS = leistungInPS;
    }
    
    // Методы (возможности)
    public void beschleunigen() {
        System.out.println("Das " + farbe + "e Auto beschleunigt");
    }
    
    public void bremsen() {
        System.out.println("Das " + farbe + "e Auto bremst");
    }
    
    // Getter и Setter
    public String getFarbe() { return farbe; }
    public void setFarbe(String farbe) { this.farbe = farbe; }
    public int getAnzahlTueren() { return anzahlTueren; }
    public int getLeistungInPS() { return leistungInPS; }
}

// Создание объектов (инстанцирование)
public class Main {
    public static void main(String[] args) {
        // Объект 1
        Auto meinGolf = new Auto("blau", 5, 150);
        meinGolf.beschleunigen();
        
        // Объект 2
        Auto deinA3 = new Auto("schwarz", 3, 120);
        deinA3.bremsen();
        
        System.out.println("Mein Golf: " + meinGolf.getFarbe() + ", " + 
                          meinGolf.getAnzahlTueren() + " Türen, " + 
                          meinGolf.getLeistungInPS() + " PS");
    }
}

Четыре принципа (столпы) ООП

1. Инкапсуляция (Encapsulation)

Что это? Объединение данных (атрибутов) и кода, который эти данные обрабатывает (методов), в одну единицу — класс. Доступ к данным контролируется путём их “скрытия” от внешнего мира.

Как это работает? Атрибуты обычно объявляются как private. Это означает, что снаружи класса никто не может напрямую обращаться к meinGolf.leistungInPS или изменять его. Доступ происходит только через публичные методы — getter и setter (методы доступа).

  • getLeistungInPS(): возвращает значение (чтение)
  • setLeistungInPS(int neueLeistung): изменяет значение (запись)

Почему это важно?

  • Контроль: Класс может проверить в методе set, имеет ли смысл новое значение (например, neueLeistung не должна быть отрицательной)
  • Поддерживаемость: Если внутреннее представление изменится (скажем, ты сохраняешь мощность в кВт вместо л.с.), нужно менять только getter/setter, а не весь код, использующий эти значения
  • Консистентность данных: Предотвращает попадание объекта в невалидное состояние
// Пример инкапсуляции
public class Bankkonto {
    // Приватные атрибуты — недоступны снаружи
    private double kontostand;
    private String kontonummer;
    private String inhaber;
    
    public Bankkonto(String kontonummer, String inhaber, double startbetrag) {
        this.kontonummer = kontonummer;
        this.inhaber = inhaber;
        this.kontostand = Math.max(0, startbetrag); // Баланс не может быть отрицательным
    }
    
    // Getter — контролируемый доступ на чтение
    public double getKontostand() {
        return kontostand;
    }
    
    // Setter — контролируемый доступ на запись с валидацией
    public void setKontostand(double neuerKontostand) {
        if (neuerKontostand >= 0) {
            this.kontostand = neuerKontostand;
        } else {
            System.out.println("Fehler: Kontostand darf nicht negativ sein!");
        }
    }
    
    // Бизнес-метод с инкапсуляцией
    public void hebeGeldAb(double betrag) {
        if (betrag > 0 && kontostand >= betrag) {
            kontostand -= betrag;
            System.out.println("Abhebung erfolgreich. Neuer Kontostand: " + kontostand);
        } else {
            System.out.println("Abhebung nicht möglich. Ungültiger Betrag oder unzureichendes Guthaben.");
        }
    }
    
    public void zahleEin(double betrag) {
        if (betrag > 0) {
            kontostand += betrag;
            System.out.println("Einzahlung erfolgreich. Neuer Kontostand: " + kontostand);
        } else {
            System.out.println("Einzahlung nicht möglich. Betrag muss positiv sein.");
        }
    }
}

2. Наследование (Inheritance)

Что это? Возможность создать новый класс (дочерний класс или подкласс) на основе уже существующего класса (родительский класс или суперкласс). Дочерний класс наследует все атрибуты и методы родительского класса.

Зачем это нужно? Чтобы избежать повторения кода (принцип DRY: Don’t Repeat Yourself) и моделировать иерархические отношения.

Пример:

  • Суперкласс: Fahrzeug (с атрибутами geschwindigkeit, hersteller и методом bewege())
  • Подкласс: Auto (наследует от Fahrzeug и добавляет свой атрибут anzahlTueren)
  • Подкласс: Fahrrad (наследует от Fahrzeug и добавляет свой атрибут anzahlGaenge)

Объект Auto автоматически имеет geschwindigkeit и может использовать bewege().

// Пример наследования
// Суперкласс (базовый класс)
public class Fahrzeug {
    protected String hersteller;
    protected int geschwindigkeit;
    protected int baujahr;
    
    public Fahrzeug(String hersteller, int baujahr) {
        this.hersteller = hersteller;
        this.baujahr = baujahr;
        this.geschwindigkeit = 0;
    }
    
    public void beschleunigen(int increment) {
        this.geschwindigkeit += increment;
        System.out.println(hersteller + " beschleunigt auf " + geschwindigkeit + " km/h");
    }
    
    public void bremsen(int decrement) {
        this.geschwindigkeit = Math.max(0, geschwindigkeit - decrement);
        System.out.println(hersteller + " bremst auf " + geschwindigkeit + " km/h");
    }
    
    public void bewege() {
        System.out.println("Das " + hersteller + " Fahrzeug bewegt sich mit " + geschwindigkeit + " km/h");
    }
    
    // Getter
    public String getHersteller() { return hersteller; }
    public int getGeschwindigkeit() { return geschwindigkeit; }
    public int getBaujahr() { return baujahr; }
}

// Подкласс 1
public class Auto extends Fahrzeug {
    private int anzahlTueren;
    private String kraftstoffart;
    
    public Auto(String hersteller, int baujahr, int anzahlTueren, String kraftstoffart) {
        super(hersteller, baujahr); // Вызов конструктора суперкласса
        this.anzahlTueren = anzahlTueren;
        this.kraftstoffart = kraftstoffart;
    }
    
    // Собственный метод подкласса
    public void hupen() {
        System.out.println("Das " + hersteller + " Auto hupt!");
    }
    
    // Переопределение метода суперкласса
    @Override
    public void bewege() {
        System.out.println("Das " + anzahlTueren + "-türige " + hersteller + 
                          " Auto fährt auf der Straße mit " + geschwindigkeit + " km/h");
    }
    
    // Getter
    public int getAnzahlTueren() { return anzahlTueren; }
    public String getKraftstoffart() { return kraftstoffart; }
}

// Подкласс 2
public class Fahrrad extends Fahrzeug {
    private int anzahlGaenge;
    private String fahrzeugtyp = "Fahrrad";
    
    public Fahrrad(String hersteller, int baujahr, int anzahlGaenge) {
        super(hersteller, baujahr);
        this.anzahlGaenge = anzahlGaenge;
    }
    
    // Собственный метод
    public void schalten(int gang) {
        if (gang >= 1 && gang <= anzahlGaenge) {
            System.out.println("Schalte in Gang " + gang);
        } else {
            System.out.println("Ungültiger Gang!");
        }
    }
    
    // Переопределение метода
    @Override
    public void bewege() {
        System.out.println("Das " + hersteller + " Fahrrad mit " + anzahlGaenge + 
                          " Gängen bewegt sich mit " + geschwindigkeit + " km/h");
    }
}

3. Полиморфизм

Что это? Объект подкласса может обрабатываться как объект его надкласса. Методы переопределяются в подклассах, чтобы реализовать специфическое поведение.

Пример: метод bewege() определён в надклассе Fahrzeug. В классе Auto он переопределён, чтобы выводить “Das Auto fährt auf der Straße”. В классе Flugzeug (который также наследует Fahrzeug) переопределение выводит “Das Flugzeug fliegt durch die Luft”.

Преимущество: код, вызывающий метод bewege(), не нужно знать конкретный тип объекта (Auto или Flugzeug). Просто вызываем bewege() на объекте типа Fahrzeug. При выполнении программы автоматически запускается переопределённый метод из фактического класса объекта. Это делает код чрезвычайно гибким.

// Beispiel für Polymorphie
public class PolymorphieDemo {
    public static void main(String[] args) {
        // Verschiedene Fahrzeug-Objekte
        Fahrzeug meinAuto = new Auto("VW", 2020, 4, "Benzin");
        Fahrzeug meinFahrrad = new Fahrrad("Cube", 2021, 21);
        Fahrzeug meinMotorrad = new Motorrad("Yamaha", 2019, 600);
        
        // Polymorphie: Alle werden als Fahrzeug behandelt
        Fahrzeug[] fahrzeuge = {meinAuto, meinFahrrad, meinMotorrad};
        
        // Dynamische Bindung: Zur Laufzeit wird die richtige Methode aufgerufen
        for (Fahrzeug fahrzeug : fahrzeuge) {
            fahrzeug.beschleunigen(50);
            fahrzeug.bewege();  // Ruft die überschriebene Methode der jeweiligen Subklasse auf
            fahrzeug.bremsen(20);
            System.out.println("---");
        }
        
        // Typ-Prüfung und Downcasting
        for (Fahrzeug fahrzeug : fahrzeuge) {
            if (fahrzeug instanceof Auto) {
                Auto auto = (Auto) fahrzeug;  // Downcasting
                auto.hupen();
            } else if (fahrzeug instanceof Fahrrad) {
                Fahrrad fahrrad = (Fahrrad) fahrzeug;
                fahrrad.schalten(5);
            }
        }
    }
}

// Zusätzliche Subklasse für das Beispiel
class Motorrad extends Fahrzeug {
    private int hubraum;
    
    public Motorrad(String hersteller, int baujahr, int hubraum) {
        super(hersteller, baujahr);
        this.hubraum = hubraum;
    }
    
    @Override
    public void bewege() {
        System.out.println("Das " + hersteller + " Motorrad mit " + hubraum + 
                          " ccm fährt mit " + geschwindigkeit + " km/h");
    }
    
    public void wheelie() {
        System.out.println("Das " + hersteller + " Motorrad macht ein Wheelie!");
    }
}

4. Абстракция

Что это? Принцип сведения сложной реальности к существенным для контекста свойствам и скрывания ненужных деталей.

Пример: когда моделируешь автомобиль как объект Auto, ориентируешься на атрибуты вроде leistung и методы вроде bremsen(). Детали того, как именно работает тормоз (гидравлика, тормозные колодки и прочее), для большинства программ не важны и “абстрагируются”. Просто вызываешь bremsen().

Абстракция достигается двумя основными способами:

  1. Абстрактные классы: классы, которые нельзя инстанцировать, а только использовать как шаблон для других классов. Они могут определять абстрактные методы (методы без реализации, которые подклассы должны реализовать).
  2. Интерфейсы: см. следующий раздел.
// Beispiel für Abstraktion
// Abstrakte Klasse
public abstract class Tier {
    protected String name;
    protected int alter;
    
    public Tier(String name, int alter) {
        this.name = name;
        this.alter = alter;
    }
    
    // Konkrete Methode
    public void schlafen() {
        System.out.println(name + " schläft.");
    }
    
    public void fressen() {
        System.out.println(name + " frisst.");
    }
    
    // Abstrakte Methoden - müssen von Subklassen implementiert werden
    public abstract void machGeraeusch();
    public abstract void bewegeDich();
    
    // Getter
    public String getName() { return name; }
    public int getAlter() { return alter; }
}

// Konkrete Subklassen
public class Hund extends Tier {
    private String rasse;
    
    public Hund(String name, int alter, String rasse) {
        super(name, alter);
        this.rasse = rasse;
    }
    
    @Override
    public void machGeraeusch() {
        System.out.println(name + " bellt: Wuff! Wuff!");
    }
    
    @Override
    public void bewegeDich() {
        System.out.println(name + " läuft auf vier Beinen.");
    }
    
    public void apportieren() {
        System.out.println(name + " apportiert den Ball.");
    }
}

public class Katze extends Tier {
    private String fellfarbe;
    
    public Katze(String name, int alter, String fellfarbe) {
        super(name, alter);
        this.fellfarbe = fellfarbe;
    }
    
    @Override
    public void machGeraeusch() {
        System.out.println(name + " miaut: Miau!");
    }
    
    @Override
    public void bewegeDich() {
        System.out.println(name + " schleicht sich an.");
    }
    
    public void kratzen() {
        System.out.println(name + " kratzt am Kratzbaum.");
    }
}

Важные понятия ООП

Атрибут

Переменная, которая описывает состояние или свойство объекта (например, farbe, alter, kontostand).

Метод

Функция или процедура, определённая в классе и описывающая поведение объекта (например, bezahlen(), druckeDokument()). Вызов метода (или сообщение) — это обращение к объекту с просьбой выполнить определённый метод (например, meinKonto.hebeGeldAb(50)).

Персистентность

Долговременное сохранение состояния объектов (их значений атрибутов) таким образом, чтобы это состояние сохранялось после завершения программы. Обычно данные сохраняются в базе данных или файле. Сам объект существует только в оперативной памяти (RAM) во время выполнения программы.

// Beispiel für Persistenz
import java.io.*;
import java.util.*;

public class PersistenzBeispiel {
    
    // Objekt speichern
    public static void speichereKonto(Bankkonto konto, String dateiname) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(dateiname))) {
            oos.writeObject(konto);
            System.out.println("Konto wurde gespeichert in " + dateiname);
        } catch (IOException e) {
            System.out.println("Fehler beim Speichern: " + e.getMessage());
        }
    }
    
    // Objekt laden
    public static Bankkonto ladeKonto(String dateiname) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(dateiname))) {
            Bankkonto konto = (Bankkonto) ois.readObject();
            System.out.println("Konto wurde geladen aus " + dateiname);
            return konto;
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("Fehler beim Laden: " + e.getMessage());
            return null;
        }
    }
    
    public static void main(String[] args) {
        Bankkonto meinKonto = new Bankkonto("DE123456789", "Max Mustermann", 1000.0);
        meinKonto.zahleEin(500.0);
        
        // Speichern
        speichereKonto(meinKonto, "konto.ser");
        
        // Laden
        Bankkonto geladenesKonto = ladeKonto("konto.ser");
        if (geladenesKonto != null) {
            System.out.println("Geladenes Konto - Kontostand: " + geladenesKonto.getKontostand());
        }
    }
}

// Serializable Interface für Persistenz
class Bankkonto implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private double kontostand;
    private String kontonummer;
    private String inhaber;
    
    // ... restliche Implementierung wie oben
}

Интерфейс / API

(Внимание: этот термин имеет двойное значение!)

  1. В общем смысле: Интерфейс (или API - Application Programming Interface) определяет описание контракта, что может делать что-то, без указания как это делается. Это набор сигнатур методов (имя, параметры, тип возвращаемого значения).

  2. Как языковая конструкция (interface): Специальная языковая конструкция в ООП-языках, которая формально определяет именно такие контракты. Класс, реализующий interface, должен реализовать все определённые в нём методы (заполнить их кодом).

Различие: класс vs. интерфейс

ПризнакКлассИнтерфейс
Что это?Чертёж для объектовКонтракт или спецификация способностей
Содержит…Реализацию (код методов), атрибуты, конструкторыТолько сигнатуры методов (имя, параметры, тип возвращаемого значения) без реализации (без тела кода)
Ключевые словаclass, extends (наследование)interface, implements (реализация)
НаследованиеКласс может наследовать от одного другого класса (простое наследование)Класс может реализовать несколько интерфейсов
ИнстанцированиеМожет быть создан с помощью new (создание объектов)НЕВОЗМОЖНО инстанцировать
НазначениеРеализовать состояние и поведениеОпределить поведение

Аналогия

  • Класс = конкретный сотрудник: “Макс Мюллер, разработчик ПО” знает SAP и может писать Java-код (реализация)
  • Интерфейс = объявление о вакансии: “Ищем Java-разработчика со знанием SAP”. Он только перечисляет требования (навыки), которые должен иметь кандидат
// Пример интерфейса
interface Fliegend {
    void fliegen();
    void landen();
}

interface Schwimmend {
    void schwimmen();
    void tauchen();
}

// Класс реализует несколько интерфейсов
public class Ente implements Fliegend, Schwimmend {
    private String name;
    
    public Ente(String name) {
        this.name = name;
    }
    
    // Реализуем методы интерфейса
    @Override
    public void fliegen() {
        System.out.println(name + " fliegt in die Luft");
    }
    
    @Override
    public void landen() {
        System.out.println(name + " landet auf dem Wasser");
    }
    
    @Override
    public void schwimmen() {
        System.out.println(name + " schwimmt elegant");
    }
    
    @Override
    public void tauchen() {
        System.out.println(name + " taucht nach Fischen");
    }
    
    // Собственный метод
    public void quaken() {
        System.out.println(name + " quakt: Quak! Quak!");
    }
}

// Полиморфизм с интерфейсами
public class InterfaceDemo {
    public static void main(String[] args) {
        Ente meineEnte = new Ente("Donald");
        
        // Обращаемся как с уткой
        meineEnte.quaken();
        
        // Обращаемся как с летающим существом
        Fliegend fliegendeEnte = meineEnte;
        fliegendeEnte.fliegen();
        fliegendeEnte.landen();
        
        // Обращаемся как с плывущим существом
        Schwimmend schwimmendeEnte = meineEnte;
        schwimmendeEnte.schwimmen();
        schwimmendeEnte.tauchen();
    }
}

Различие: библиотека классов vs. фреймворк

Это важное концептуальное различие, которое часто спрашивают на экзаменах.

Библиотека классов (Library / SDK)

  • Ты контролируешь поток выполнения. Библиотека — это набор готовых классов и методов, которые ты используешь в своём коде так, как считаешь нужным.
  • Аналогия: ящик с инструментами. Ты строишь полку и берёшь из ящика молоток (Hammerklasse.schlagZu()), потом пилу (Saegeklasse.saege()). Ты определяешь порядок и цель.
  • Примеры: Java Standard Library, Apache Commons, jQuery.

Фреймворк

  • Фреймворк контролирует поток выполнения. Фреймворк — это основной скелет или структура для определённого типа приложения. Ты заполняешь предусмотренные места своим кодом. Фреймворк вызывает твой код (принцип Hollywood Principle: “Don’t call us, we’ll call you”).
  • Аналогия: Фреймворк — это проект целого дома со встроенными стенами и проводкой. Тебе остаётся только установить розетки и выбрать обои (то есть вписать свой код в предопределённые методы). Проект (фреймворк) определяет ход работы.
  • Примеры: Spring (Java), .NET Framework, Angular, React (Web), JUnit (Testing).

Коротко: ты используешь библиотеку. Ты работаешь в фреймворке.

// Пример библиотеки vs. фреймворк

// Библиотека: ты вызываешь методы
import java.util.ArrayList;
import java.util.Collections;

public class BibliothekBeispiel {
    public static void main(String[] args) {
        // Ты определяешь поток выполнения
        ArrayList<String> namen = new ArrayList<>();
        namen.add("Alice");
        namen.add("Bob");
        namen.add("Charlie");
        
        // Ты используешь методы библиотеки когда захочешь
        Collections.sort(namen);
        System.out.println("Sortierte Namen: " + namen);
    }
}

// Фреймворк: фреймворк вызывает твой код
// Пример с JUnit Testing Framework
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class FrameworkBeispiel {
    
    @Test  // Фреймворк вызывает этот метод
    public void testAddition() {
        // Ты заполняешь предопределённый метод своим кодом
        int result = 2 + 3;
        assertEquals(5, result, "2 + 3 sollte 5 ergeben");
    }
    
    @Test  // Ещё один метод, который вызовет фреймворк
    public void testSubtraction() {
        int result = 10 - 4;
        assertEquals(6, result, "10 - 4 sollte 6 ergeben");
    }
}

Резюме для экзамена IHK

  • Класс vs. объект: чертёж vs. конкретная вещь
  • Четыре принципа:
    • Инкапсуляция: скрывай данные, предоставляй контролируемый доступ
    • Наследование: наследуй свойства и методы, избегай повторения кода
    • Полиморфизм: переопредели методы для подтипоспецифичного поведения
    • Абстракция: скрывай ненужные детали
  • Интерфейс vs. класс: интерфейс определяет что, класс определяет как
  • Библиотека vs. фреймворк: ты используешь библиотеку, фреймворк использует тебя

Концепции, актуальные для экзамена

Важные различия

КонцепцияОписаниеАктуально для экзамена
КлассЧертёж для объектов
Объект/ЭкземплярКонкретное воплощение класса
АтрибутСвойство объекта
МетодПоведение объекта
НаследованиеПереиспользование кода через иерархию
ПолиморфизмМногообразие через переопределение
ИнкапсуляцияСкрытие данных с getter/setter
АбстракцияСнижение сложности

Типичные экзаменационные задачи

  1. Объясните различие между классом и объектом
  2. Опишите четыре принципа ООП
  3. Реализуйте простую иерархию наследования
  4. Объясните инкапсуляцию с getter/setter-методами
  5. Различите интерфейс и класс
  6. Сравните библиотеку и фреймворк

Эти основы критически важны для понимания современной разработки ПО и служат основой для продвинутых концепций вроде Design Patterns, фреймворков и архитектурных принципов.

Продолжение пути обучения OOP

Следующий материал в пути обучения OOP охватывает Отношения между классами в OOP: Ассоциация, Агрегация, Композиция и Наследование для экзамена IHK — отношения между классами для подготовки к экзамену IHK.

Назад к блогу
Share:

Похожие статьи