Основы ООП: Класс, объект, экземпляр и методы для экзамена 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().
Абстракция достигается двумя основными способами:
- Абстрактные классы: классы, которые нельзя инстанцировать, а только использовать как шаблон для других классов. Они могут определять абстрактные методы (методы без реализации, которые подклассы должны реализовать).
- Интерфейсы: см. следующий раздел.
// 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
(Внимание: этот термин имеет двойное значение!)
-
В общем смысле: Интерфейс (или API - Application Programming Interface) определяет описание контракта, что может делать что-то, без указания как это делается. Это набор сигнатур методов (имя, параметры, тип возвращаемого значения).
-
Как языковая конструкция (
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 | ✅ |
| Абстракция | Снижение сложности | ✅ |
Типичные экзаменационные задачи
- Объясните различие между классом и объектом
- Опишите четыре принципа ООП
- Реализуйте простую иерархию наследования
- Объясните инкапсуляцию с getter/setter-методами
- Различите интерфейс и класс
- Сравните библиотеку и фреймворк
Эти основы критически важны для понимания современной разработки ПО и служат основой для продвинутых концепций вроде Design Patterns, фреймворков и архитектурных принципов.
Продолжение пути обучения OOP
Следующий материал в пути обучения OOP охватывает Отношения между классами в OOP: Ассоциация, Агрегация, Композиция и Наследование для экзамена IHK — отношения между классами для подготовки к экзамену IHK.

