Einführungsphase

E3 – Grundlagen der Programmierung

Programmieren als Werkzeug für Modellierung und Problemlösen

Das Themenfeld E3 Grundlagen der Programmierung ist ein zentrales Arbeitsfeld der Einführungsphase. Im Mittelpunkt steht nicht nur das Erlernen einzelner Java-Befehle, sondern der systematische Weg von der Problemstellung zur nachvollziehbaren Lösung.

Die Programmiersprache wird dabei als Mittel zum Zweck genutzt: Sie hilft, Modelle zu präzisieren, Algorithmen umzusetzen und Ergebnisse zu prüfen. Spätere Themenfelder und Projekte bauen auf diesen Grundlagen auf.

Die Kapitel folgen daher einer durchgehenden Lernlinie: Werte und Typen verstehen → Abläufe steuern → Teilaufgaben mit Methoden strukturieren → Daten in Arrays und Strings organisieren → Such- und Sortieralgorithmen entwickeln.

Kerncurriculum
Kerncurriculum kompakt
Einordnung und Inhalte des Themenfelds E.3

A) Allgemeine Einordnung

Programmierung gehört in der Einführungsphase zu den zentralen Primärerfahrungen der Informatik. Lernende entwickeln dabei vor allem Modellierungs- und Problemlösekompetenz, indem sie schrittweise von einer Idee zu einer überprüfbaren Umsetzung gelangen.

Java wird als objektorientierte Sprache genutzt, in E3 steht jedoch zunächst die prozedurale Grundarbeit mit Datentypen, Ausdrücken, Kontrollstrukturen und Methoden im Vordergrund.

B) Inhalte des Themenfelds E.3

C) Bedeutung für diese Kursseite

Diese Seite ist bewusst als ausbaubares Gerüst angelegt. Die Kapitel bilden eine sachlogische Lernfolge: vom Aufbau einfacher Programme über Datentypen und Ausdrücke bis zu Kontrollstrukturen, Methoden und ersten grafischen Anwendungen.

Inhalte, Beispiele und Aufgaben werden in den Unterkapiteln schrittweise ergänzt.

Quelle

Hessisches Ministerium für Kultus, Bildung und Chancen (2024): Kerncurriculum gymnasiale Oberstufe Informatik, Themenfeld E.3. Fachliche Strukturorientierung ergänzt durch das begleitende Java-Skript.

Programmiergrundlagen
Einführung in Java und Aufbau einfacher Programme
Wie Programme geschrieben, übersetzt und als Folge von Anweisungen aufgebaut werden

Übergang: Wir starten mit der kleinsten lauffähigen Programmeinheit. Damit wird die Grundlage gelegt, auf der im nächsten Schritt Variablen, Datentypen und Berechnungen sinnvoll aufgebaut werden.

1. Konzeptklärung: Programm, Quelltext und Ausführung

Ein Programm ist eine formal beschriebene Folge ausführbarer Anweisungen zur Lösung eines Problems. In Java wird diese Beschreibung als Quelltext in .java-Dateien notiert. Der Quelltext ist menschenlesbar, aber nicht direkt maschinenausführbar.

Begriff: Quelltext

Der Quelltext ist die von Menschen formulierte, syntaktisch geregelte Beschreibung eines Programms.

2. Strukturelle Einordnung: Übersetzung und Laufzeit

Java-Programme durchlaufen zwei klar getrennte Schritte. Zunächst übersetzt der Compiler den Quelltext in Bytecode (.class), anschließend führt die Java Virtual Machine (JVM) diesen Bytecode aus. Die Trennung von Übersetzung und Ausführung macht nachvollziehbar, warum Übersetzungsfehler und Laufzeitfehler unterschiedliche Ursachen haben.

Begriff: Compiler

Ein Compiler überprüft die Syntax des Quelltexts und erzeugt aus korrektem Java-Code Bytecode.

Begriff: Bytecode

Bytecode ist die plattformunabhängige Zwischenform eines Java-Programms, die von der JVM ausgeführt wird.

3. Formale Umsetzung: Klasse, main-Methode und Anweisung

Eine ausführbare Java-Anwendung besitzt mindestens eine Klasse mit einer main-Methode als Startpunkt. Die Anweisungen innerhalb von main werden in der notierten Reihenfolge ausgeführt.

Begriff: Klasse

Eine Klasse ist ein Bauplan, der Daten und Operationen in einer gemeinsamen Struktur zusammenfasst.

Begriff: main-Methode

Die main-Methode ist der definierte Einstiegspunkt einer Java-Anwendung (public static void main(String[] args)).

Begriff: Anweisung

Eine Anweisung ist ein einzelner ausführbarer Programmschritt; einfache Anweisungen enden in Java mit einem Semikolon.

4. Beispiel: Minimales, vollständiges Java-Programm

public class HalloWelt {
    public static void main(String[] args) {
        System.out.println("Hallo Welt");
    }
}

Das Beispiel enthält genau eine Klasse, genau eine Startmethode und genau eine auszuführende Anweisung. Damit ist die grundlegende Programmstruktur vollständig sichtbar, ohne zusätzliche Sprachelemente vorwegzunehmen.

5. Typische Fehlvorstellungen

Häufig wird angenommen, die Datei werde „Zeile für Zeile“ ohne Struktur ausgeführt. Tatsächlich startet die Ausführung an der main-Methode, nicht am Anfang der Datei.

Ebenfalls verbreitet ist die Gleichsetzung von Quelltext und lauffähigem Programm. Der Quelltext muss zuerst erfolgreich übersetzt werden; erst der erzeugte Bytecode ist ausführbar.

Nachschärfung

Die Darstellung trennt nun ausdrücklich zwischen Konzept (Programm als Anweisungsfolge), formaler Syntax (Klasse und main-Signatur) und technischem Prozess (Compiler/JVM), um typische Vermischungen dieser Ebenen zu vermeiden.

Nächster Schritt: Auf dieser Struktur werden nun Werte eingeführt: Variablen und Datentypen machen Programmzustände explizit und berechenbar.

EVA-Prinzip
EVA-Prinzip als Grundmodell für Programme
Programmabläufe fachlich strukturieren: Eingabe, Verarbeitung, Ausgabe

Bevor einzelne Sprachelemente wie Variablen, Datentypen oder Kontrollstrukturen im Detail betrachtet werden, hilft ein fachliches Strukturmodell für den gesamten Ablauf eines Programms: das EVA-Prinzip.

1. Grundidee: Drei funktionale Perspektiven auf Programmlogik

  • Eingabe: Daten gelangen ins Programm.
  • Verarbeitung: Daten werden geprüft, verändert, berechnet oder interpretiert.
  • Ausgabe: Ergebnisse werden sichtbar gemacht oder weitergegeben.
Merksatz

Gute Programme trennen möglichst klar zwischen Eingabe, Verarbeitung und Ausgabe.

Das EVA-Prinzip ist damit ein hilfreiches erstes Strukturmodell, aber noch kein vollständiges Modell moderner Softwareentwicklung. Aspekte wie Objektstruktur, Zustandsverwaltung, Nebenläufigkeit oder komplexe Ereignisverarbeitung kommen später ergänzend hinzu.

Für den Einstieg sind Konsolenprogramme besonders geeignet, weil die EVA-Teile dort klar sichtbar sind; dieselben Grundideen kehren später auch in GUI- und ereignisgesteuerten Programmen wieder.

Sequenzdiagramm: EVA als GUI-Ereignisfolge

Auch bei grafischen Oberflächen bleibt die EVA-Logik erhalten: Ein Ereignis löst Verarbeitung aus, die anschließend in einer sichtbaren Ausgabe endet.

Sequenzdiagramm eines GUI-Ereignisses im EVA-Prinzip von Nutzereingabe bis UI-Ausgabe

2. Beispiel: Namen einlesen und begrüßen

name = input("Wie heißt du? ")
gruss = f"Hallo, {name}!"
print(gruss)
  • Eingabe: input(...) liest den Namen ein.
  • Verarbeitung: Der Begrüßungstext wird zusammengesetzt.
  • Ausgabe: print(...) gibt den Text aus.

3. Beispiel: Zwei Zahlen einlesen und addieren

a = float(input("Erste Zahl: "))
b = float(input("Zweite Zahl: "))
summe = a + b
print("Summe:", summe)
  • Eingabe: Zwei Zahlen werden eingelesen.
  • Verarbeitung: Die Berechnung a + b wird durchgeführt.
  • Ausgabe: Die berechnete Summe wird angezeigt.

4. Beispiel: Alter abfragen und mit if auswerten

alter = int(input("Wie alt bist du? "))

if alter >= 18:
    meldung = "Du bist volljährig."
else:
    meldung = "Du bist minderjährig."

print(meldung)
  • Eingabe: Das Alter wird eingelesen.
  • Verarbeitung: Eine if-Kontrollstruktur bewertet das Alter.
  • Ausgabe: Die passende Meldung wird ausgegeben.

5. Beispiel: Punktzahl mit Funktion bewerten

def bewerte_punktzahl(punkte):
    if punkte >= 90:
        return "sehr gut"
    if punkte >= 75:
        return "gut"
    return "ausreichend"

punkte = int(input("Punktzahl: "))
urteil = bewerte_punktzahl(punkte)
print("Bewertung:", urteil)
  • Eingabe: Die Punktzahl wird eingelesen.
  • Verarbeitung: Eine Funktion ordnet die Punktzahl einer Kategorie zu.
  • Ausgabe: Die Bewertung wird ausgegeben.
Datentypen und Variablen
Variablen, Zuweisungen und Datentypen
Werte speichern, verändern und passend typisieren

Übergang: Nach Programmgrundstruktur (Kapitel 1) und erstem Ablaufmodell über das EVA-Prinzip (Kapitel 1a) geht es jetzt um den Inhalt der Anweisungen: Werte speichern, verändern und mit passenden Typen absichern.

1. Konzeptklärung: Variable als benannter Speicherort

Eine Variable bezeichnet einen Speicherbereich, dem ein Name zugeordnet ist. Der Name ermöglicht den Zugriff auf den aktuell gespeicherten Wert im Programmablauf.

Begriff: Variable

Eine Variable ist ein benannter Speicherort mit festgelegtem Datentyp und veränderlichem Wert.

2. Strukturelle Einordnung: Zustand im Programm

Variablen machen Programmzustände explizit. Während ein Programm ausgeführt wird, werden Werte gelesen, berechnet und erneut gespeichert. Dadurch lassen sich Zwischenergebnisse nachvollziehbar darstellen und weiterverarbeiten.

3. Formale Umsetzung: Deklaration, Initialisierung und Zuweisung

Die Deklaration legt Datentyp und Namen fest. Eine Initialisierung weist beim Anlegen bereits einen Startwert zu. Eine spätere Zuweisung ersetzt den bisherigen Wert der Variablen.

Begriff: Zuweisung

Eine Zuweisung ordnet einer Variablen mit dem Operator = einen neuen Wert zu und verändert damit den Programmzustand.

Begriff: Datentyp

Ein Datentyp legt den zulässigen Wertebereich und die erlaubten Operationen für eine Variable fest.

public class VariablenDemo {
    public static void main(String[] args) {
        int kontoStand = 100;      // Deklaration + Initialisierung
        kontoStand = kontoStand + 25; // Zuweisung: Zustand ändert sich

        double temperatur = 21.5;
        boolean istVoll = false;
        char note = 'A';

        System.out.println(kontoStand);
    }
}

4. Datentypen in Java: Übersicht der primitiven Typen

Die folgenden acht primitiven Datentypen sind fest in Java definiert. Sie speichern einfache Werte direkt und besitzen feste Größen und Wertebereiche.

Datentyp Größe Wertebereich Standardwert
booleanJVM-abhängig (logisch 1 Bit)true, falsefalse
char16 BitU+0000 bis U+FFFF'\u0000'
byte8 Bit-128 bis 1270
short16 Bit-32.768 bis 32.7670
int32 Bit-2.147.483.648 bis 2.147.483.6470
long64 Bit-9.223.372.036.854.775.808 bis 9.223.372.036.854.775.8070L
float32 Bitca. ±1,4E-45 bis ±3,4E+380.0f
double64 Bitca. ±4,9E-324 bis ±1,7E+3080.0d

5. Primitive Datentypen und Objekte sauber unterscheiden

Primitive Typen speichern unmittelbare Einzelwerte (z. B. Zahl, Zeichen, Wahrheitswert). Bei Referenztypen verweist eine Variable dagegen auf ein Objekt, das intern mehrere Daten und ggf. Methodenbezug zusammenfasst.

int punkte = 42;                  // primitiver Wert liegt direkt vor
int[] messwerte = {3, 5, 8};      // Variable speichert Referenz auf ein Array-Objekt
String name = "Lea";              // Referenz auf ein String-Objekt

Diese Unterscheidung ist für spätere Kapitel zentral: Arrays und andere Datenstrukturen arbeiten mit Referenzen auf Objekte, während numerische Berechnungen häufig auf primitiven Typen stattfinden.

6. Typumwandlung

Bei der Typumwandlung wird ein Wert in einen anderen Datentyp überführt. Java unterscheidet automatische (implizite) Umwandlung und explizites Casting.

Numerische Typen: von kleiner zu größer byte short int long float double meist implizit möglich (Widening) Rückrichtung: explizites Casting nötig, ggf. Informationsverlust
Von links nach rechts ist die Umwandlung typischerweise automatisch möglich; in Gegenrichtung nur mit explizitem Casting und möglichem Genauigkeits- oder Werteverlust.
Automatische (implizite) Umwandlung
int anzahl = 7;
double alsDouble = anzahl; // int -> double
float alsFloat = anzahl;   // int -> float
Arithmetische Beförderung bei kleinen Ganzzahltypen
byte a = 10;
short b = 20;
int summe = a + b; // byte/short werden in Ausdrücken zu int
Explizite Umwandlung (Casting)
double preis = 19.99;
int euro = (int) preis;   // 19, Nachkommastellen fallen weg

long gross = 4_000_000_000L;
int klein = (int) gross;  // Überlauf möglich

float note = 2.7f;
int ganzzahl = (int) note; // 2

7. Typische Fehlvorstellungen

Der Operator = wird oft als mathematische Gleichheit interpretiert. In Java bedeutet er Zuweisung: Der rechte Ausdruck wird ausgewertet und sein Ergebnis links gespeichert.

Ebenso verbreitet ist die Annahme, der Datentyp sei nur „Beschriftung“. Tatsächlich bestimmt der Typ, welche Werte zulässig sind, wie sie gespeichert werden und ob eine Umwandlung automatisch oder nur per Casting möglich ist.

Nachschärfung

Die Kapitelstruktur verbindet jetzt Variablenarbeit, Typsystem und Typumwandlung systematisch. Damit ist eine tragfähige Basis gelegt, um in späteren Kapiteln Datenstrukturen, Arrays und algorithmische Verarbeitung über primitive Werte und Referenzen konsistent zu behandeln.

Nächster Schritt: Mit diesen Werten lassen sich nun Ausdrücke und Bedingungen formulieren, die anschließend die Ablaufsteuerung über Kontrollstrukturen ermöglichen.

Operatoren und Bedingungen
Operatoren und logische Ausdrücke
Rechnen, vergleichen und Bedingungen formulieren

Übergang: Variablen und Datentypen liefern die Wertebasis. Jetzt wird geklärt, wie diese Werte über Operatoren zu Berechnungen, Vergleichen und Bedingungen verknüpft werden.

1. Konzeptklärung: Ausdruck als auswertbare Struktur

Ein Ausdruck kombiniert Werte, Variablen, Konstanten und Operatoren zu einer auswertbaren Einheit. Das Ergebnis eines Ausdrucks hat einen Datentyp, zum Beispiel numerisch oder boolesch. Operatoren sind damit nicht nur Rechenzeichen, sondern zentrale Bausteine zur Formulierung von Berechnungen und Bedingungen.

Begriff: Ausdruck

Ein Ausdruck ist eine Kombination aus Operanden und Operatoren, die zu einem Wert ausgewertet wird.

Begriff: Operator

Ein Operator legt fest, wie mit Operanden gerechnet, verglichen oder logisch verknüpft wird.

2. Strukturelle Einordnung: Ausdrücke im Programmablauf

Arithmetische Ausdrücke erzeugen numerische Ergebnisse, Vergleichsausdrücke erzeugen Wahrheitswerte, und logische Ausdrücke verknüpfen Wahrheitswerte zu komplexeren Bedingungen. Damit bilden sie die fachliche Brücke zwischen Datenverarbeitung und Ablaufsteuerung.

3. Formale Umsetzung: Operatorgruppen, Priorität und Klammerung

Typische arithmetische Operatoren sind +, -, *, / und %. Vergleichsoperatoren sind unter anderem ==, !=, <, <=, >, >=. Logische Operatoren wie &&, || und ! arbeiten auf booleschen Werten. Klammern steuern die Auswertungsreihenfolge explizit und reduzieren Mehrdeutigkeiten.

public class OperatorenDemo {
    public static void main(String[] args) {
        int a = 8;
        int b = 3;

        int summe = a + b * 2;                 // arithmetischer Ausdruck
        boolean istGleich = (a == b);          // Vergleichsausdruck
        boolean istGueltig = (a > b) && (b > 0); // logischer Ausdruck

        System.out.println(summe);
        System.out.println(istGleich);
        System.out.println(istGueltig);
    }
}

4. Beispielanalyse: numerisches vs. boolesches Ergebnis

a + b * 2 liefert einen numerischen Wert. a == b liefert den Wahrheitswert true oder false. (a > b) && (b > 0) verknüpft zwei boolesche Teilausdrücke zu einer Gesamtbedingung, die später in if- oder while-Strukturen verwendet werden kann.

5. Logische Operatoren in Bedingungen

Sobald Bedingungen aus mehreren Teilaussagen bestehen, werden logische Operatoren zur Verknüpfung benötigt. Sie entscheiden, ob eine Gesamtbedingung in Kontrollstrukturen wie if, while oder for als true oder false ausgewertet wird.

Name Java-Notation Java-Beispiel
Logical and&&(sum > min) && (sum < max)
Logical or||(answer == 'y') || (answer == 'Y')
Logical not!!(number < 0)

Die Tabelle zeigt die typische Rollenverteilung: && fordert, dass beide Teilbedingungen gelten, || akzeptiert mindestens eine zutreffende Bedingung, und ! negiert einen vorhandenen Wahrheitswert.

6. Wahrheitstabelle für &&, || und !

Wahrheitstabellen helfen dabei, das Verhalten logischer Operatoren exakt zu überprüfen. Gerade bei verschachtelten Bedingungen in Schleifen und Verzweigungen lässt sich so vorab prüfen, welche Kombinationen zu einer Ausführung des jeweiligen Blocks führen.

A B A && B A || B !(A)
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Für die Praxis heißt das: Bedingungen lassen sich aus mehreren Teilaussagen zusammensetzen, um Programmabläufe präzise zu steuern. Das ist zentral für Grenzprüfungen in if-Anweisungen, Abbruchkriterien in while-Schleifen und kombinierte Laufbedingungen in for-Schleifen.

7. Typische Fehlvorstellungen

Ein häufiger Fehler ist die Verwechslung von = (Zuweisung) und == (Vergleich). Dadurch wird statt einer Bedingung unbeabsichtigt ein Wert zugewiesen oder ein Syntaxfehler erzeugt.

Ebenso wird oft angenommen, jeder Ausdruck liefere eine Zahl. Vergleichs- und logische Ausdrücke liefern jedoch boolesche Werte und sind damit direkt als Bedingungen interpretierbar.

Ohne Klammerung wird die Priorität von Operatoren häufig falsch eingeschätzt. Explizite Klammern sichern die beabsichtigte Auswertungsreihenfolge.

Nachschärfung

Die Darstellung trennt jetzt systematisch zwischen Berechnung, Vergleich und logischer Verknüpfung, damit Ausdrücke als fachliche Grundlage späterer Kontrollstrukturen klar erkennbar werden.

Nächster Schritt: Diese Bedingungen werden nun genutzt, um komplette Abläufe mit Verzweigungen und Schleifen zu steuern.

Kontrollstrukturen
Kontrollstrukturen
Abläufe steuern und mit Struktogrammen systematisch modellieren

Übergang: Nach den logischen Ausdrücken folgt der nächste Schritt der Lernlinie: Aus einzelnen Bedingungen werden jetzt vollständige, steuerbare Abläufe.

A) Einführung: Was sind Kontrollstrukturen?

Kontrollstrukturen steuern den Ablauf eines Programms. Sie legen fest, ob Anweisungen nacheinander ausgeführt werden (Sequenz), ob zwischen Alternativen entschieden wird (Verzweigung) oder ob Schritte wiederholt werden (Schleife). Damit bilden sie die Brücke von einzelnen Befehlen zur algorithmischen Modellierung.

B) Struktogramm-Notation (grundlegend)

Struktogramme beschreiben Ablauflogik in Blöcken. Die Notation ist sprachneutral und passt direkt zum eingebundenen Struktogramm-Tool: Sequenz als Folge von Blöcken, Verzweigung als geteilte Entscheidung, Schleifen als wiederholte Blöcke mit Bedingung.

Struktogramm: Grundnotation

1) Bedingte Anweisung (if / if-else)

Erklärung: Eine Bedingung steuert, welcher Pfad ausgeführt wird. Bei if-else sind zwei Pfade explizit vorhanden.

if (temperatur < 0) {
    status = "Frost";
} else {
    status = "kein Frost";
}
Struktogramm-Konvention: Verzweigung

Leselogik: Was passiert hier? Es wird genau ein Zweig ausgeführt. Wie liest man das Struktogramm? Erst Bedingung prüfen, dann den passenden Pfad verfolgen.

2) While-Schleife

Erklärung: Die while-Schleife ist kopfgesteuert. Die Bedingung wird vor jedem Durchlauf geprüft.

int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}
Struktogramm-Konvention: kopfgesteuerte Schleife

Leselogik: Was passiert hier? Der Block läuft wiederholt, solange die Bedingung wahr bleibt. Wie liest man das Struktogramm? Bedingung oben, dann Schleifenkörper, danach Rücksprung zur Bedingung.

3) For-Schleife

Erklärung: Die for-Schleife bündelt Initialisierung, Bedingung und Schrittweite. Sie ist die typische Zählschleife und bereitet die Iteration über Arrays vor.

int[] werte = {7, 4, 9};
for (int i = 0; i < werte.length; i++) {
    System.out.println(werte[i]);
}
Struktogramm-Konvention: Zählschleife

Leselogik: Was passiert hier? Jeder Index wird genau einmal besucht. Wie liest man das Struktogramm? Ein Zählbereich steuert die Wiederholung, der Körper verarbeitet pro Durchlauf ein Element.

4) Do-While-Schleife

Erklärung: Die do-while-Schleife ist fußgesteuert. Der Schleifenkörper wird mindestens einmal ausgeführt.

int versuche = 0;
do {
    versuche++;
} while (versuche < 1);
Struktogramm-Konvention: fußgesteuerte Schleife

Leselogik: Was passiert hier? Ein erster Durchlauf ist garantiert, erst dann wird geprüft. Wie liest man das Struktogramm? Zuerst den Block, dann die Bedingung als Fortsetzungsentscheidung.

5) Switch-Anweisung

Erklärung: switch modelliert eine Mehrfachverzweigung und ersetzt lange Ketten verschachtelter if-Abfragen.

switch (note) {
    case 1: text = "sehr gut"; break;
    case 2: text = "gut"; break;
    default: text = "weitere";
}
Struktogramm-Konvention: Mehrfachverzweigung

Leselogik: Was passiert hier? Genau ein passender Fall wird gewählt, sonst der Default-Pfad. Wie liest man das Struktogramm? Von der Auswahlbedingung zu genau einem der Alternativpfade.

Brücke zur Algorithmik

Schleifen liefern die Iterationslogik für Arrays, Bedingungen liefern die Entscheidungslogik für Suche und Sortierung, und Struktogramme machen beides als modellierbaren Ablauf sichtbar. Damit ist der Übergang zur Strukturierung mit Methoden vorbereitet: Kontrollstrukturen werden dort als wiederverwendbare Teilabläufe gekapselt.

Nächster Schritt: Aus gesteuerten Abläufen werden nun wiederverwendbare Bausteine – Methoden als Strukturprinzip.

Methoden
Methoden, Strukturierung und erste Modellierung
Programme in sinnvoll gegliederte Bausteine zerlegen

Übergang: Kontrollstrukturen beschreiben den Ablauf – Methoden ordnen diesen Ablauf jetzt in wiederverwendbare Teilaufgaben.

1. Was ist eine Methode?

Eine Methode ist ein benannter, wiederverwendbarer Ablaufblock innerhalb einer Klasse. Sie wird nur ausgeführt, wenn sie über einen Methodenaufruf gestartet wird. Damit werden Programme nicht als „ein großer Block“, sondern als geordnete Teilaufgaben aufgebaut.

Begriff: Methode

Eine Methode bündelt eine Teilaufgabe mit klarer Schnittstelle aus Eingaben (Parameter) und optionalem Ergebnis (Rückgabewert).

2. Warum nutzt man Methoden?

Methoden verbessern Lesbarkeit, Wartbarkeit und Wiederverwendbarkeit. Wenn dieselbe Logik mehrfach gebraucht wird, wird sie einmal definiert und anschließend an mehreren Stellen aufgerufen. So entsteht ein strukturierter Übergang von linearen Programmen zu algorithmisch geplanten Lösungen.

3. Aufbau einer Methode: Methodenkopf und Methodenrumpf

Eine Methodendeklaration besteht aus Methodenkopf und Methodenrumpf. Im Kopf stehen Sichtbarkeit, ggf. static, Rückgabetyp, Name und Parameterliste. Im Rumpf steht die eigentliche Verarbeitung.

public static int berechneRabatt(int preis, int prozent) {
    int rabatt = preis * prozent / 100;
    return rabatt;
}

Leselogik: public static int berechneRabatt(int preis, int prozent) ist der Kopf. Der Block zwischen { und } ist der Rumpf.

4. Methoden aufrufen: Name + Klammern

Eine Methode wird über ihren Namen mit Klammern aufgerufen. Einmal definierte Methoden können mehrfach aufgerufen werden, auch mit unterschiedlichen Eingaben.

public static void main(String[] args) {
    begruessung();
    begruessung();
}

public static void begruessung() {
    System.out.println("Willkommen im Kurs E3.");
}

Die Methode begruessung() besitzt keine Parameter und keinen Rückgabewert. Sie führt beim Aufruf nur eine Aktion aus.

5. Parameter: Eingaben für eine Teilaufgabe

Parameter machen Methoden flexibel. Statt feste Werte im Methodenrumpf zu verwenden, werden die Werte beim Aufruf übergeben.

public static void ausgabeTicketpreis(int preis) {
    System.out.println("Ticketpreis: " + preis + " €");
}

public static void main(String[] args) {
    ausgabeTicketpreis(29);
    ausgabeTicketpreis(45);
}

Die Methode bleibt gleich, nur das Argument ändert sich. So wird dieselbe Logik für verschiedene Situationen genutzt.

6. Rückgabewerte, return und void

Methoden mit Rückgabetyp liefern ein Ergebnis an die Aufrufstelle zurück. Das Ergebnis wird über return zurückgegeben. Bei void-Methoden steht die Aktion im Vordergrund, nicht ein berechneter Rückgabewert.

// Methode mit Rückgabewert
public static int berechneGesamtpreis(int preisProTicket, int anzahl) {
    return preisProTicket * anzahl;
}

// void-Methode
public static void zeigeHinweis() {
    System.out.println("Bitte Anzahl überprüfen.");
}

public static void main(String[] args) {
    int gesamt = berechneGesamtpreis(40, 3);
    System.out.println("Gesamtpreis: " + gesamt);
    zeigeHinweis();
}

Modellierungsbezug: Berechnungen (z. B. Preise, Zeiten, Indizes) eignen sich oft für Methoden mit Rückgabewert, während Statusmeldungen oder Ausgaben häufig als void-Methoden formuliert werden.

7. static im aktuellen E3-Kontext

In E3 werden viele Beispiele innerhalb einer Klasse mit main umgesetzt. Damit main eine Methode direkt aufrufen kann, wird sie in diesem Kontext meist als static notiert. Didaktisch genügt hier: static bedeutet, dass die Methode zur Klasse gehört und ohne erzeugtes Objekt nutzbar ist.

8. Methoden als Strukturierungsprinzip

Größere Programme werden in fachlich sinnvolle Teilaufgaben zerlegt: Eingaben prüfen, Werte berechnen, Ergebnisse ausgeben. Dadurch wird der Programmablauf besser lesbar und leichter wartbar. Diese Denkweise verbindet Methoden direkt mit Kontrollstrukturen, Datenstrukturen und späteren Algorithmus-Kapiteln. Auch im Struktogramm kann ein Methodenaufruf als Blockaufruf modelliert werden.

public static boolean istGueltigerIndex(int index, int[] daten) {
    return index >= 0 && index < daten.length;
}

public static int leseWertSicher(int index, int[] daten) {
    if (istGueltigerIndex(index, daten)) {
        return daten[index];
    }
    return -1;
}

Hier ruft eine Methode eine andere auf. Kontrollstruktur (if) und Datenstruktur (int[]) werden sauber in Teilaufgaben gegliedert.

9. Methodenüberladung in tragfähigem Umfang

Bei der Methodenüberladung haben Methoden denselben Namen, aber unterschiedliche Parameterlisten. Der Name beschreibt die fachliche Aufgabe, die Parameterliste die konkrete Variante.

public static int addiere(int a, int b) {
    return a + b;
}

public static double addiere(double a, double b) {
    return a + b;
}

Die Aufrufe addiere(3, 4) und addiere(2.5, 1.5) wählen automatisch die passende Methode. Für E3 reicht dieses Grundverständnis; weiterführende Spezialfälle folgen später.

10. Typische Fehlvorstellungen (kompakt)

Methoden werden nicht automatisch ausgeführt, sondern nur durch Aufruf. Parameter sind lokal und keine globalen Variablen. Ein Rückgabewert entsteht nur bei Methoden mit passendem Rückgabetyp und return. Methodenüberladung unterscheidet sich über die Parameterliste, nicht über den Methodennamen allein.

Nächster Schritt: Die so strukturierten Teilaufgaben arbeiten nun auf größeren Datenmengen – dafür werden Arrays und Strings als Datenstrukturen benötigt.

Datenstrukturen
Datenstrukturen
Arrays und Strings als strukturierte Grundlage für algorithmisches Arbeiten

Übergang: Nach der methodischen Strukturierung folgt die Datenperspektive: Die gleiche Problemstellung wird nun nicht mehr mit Einzelwerten, sondern mit geordneten Datensammlungen bearbeitet.

A) Einführung: Warum Datenstrukturen?

Einzelne Variablen reichen nur für einzelne Werte. Sobald mehrere zusammengehörige Informationen verarbeitet werden sollen (z. B. mehrere Messwerte oder ein ganzer Text), braucht man Datenstrukturen. Sie organisieren Daten so, dass systematische Verarbeitung mit Schleifen und Bedingungen möglich wird.

Damit entsteht die fachliche Entwicklung dieses Kapitels: von einzelnen Variablen hin zu strukturierten Datensammlungen und weiter zur algorithmischen Verarbeitung.

B) Arrays als zentrale Datenstruktur

Ein Array speichert mehrere Werte gleichen Typs unter einem Namen. Die Länge ist nach der Erzeugung fest. Auf einzelne Elemente greift man über den Index zu.

// Initialisierung mit fester Länge und Startwerten
int[] messwerte = {18, 7, 42, 13, 29, 5};

// Zugriff über Index
int erstesElement = messwerte[0];
int drittesElement = messwerte[2];

Der Nutzen von Arrays liegt nicht nur in der Speicherung, sondern vor allem im geordneten Zugriff: Positionen sind eindeutig adressierbar und können deshalb gezielt geprüft, verändert oder verglichen werden.

// Durchlaufen eines Arrays mit for-Schleife
for (int i = 0; i < messwerte.length; i++) {
    System.out.println("Index " + i + " -> " + messwerte[i]);
}

Das Durchlaufen (Iterieren) über Arrays verbindet dieses Kapitel direkt mit den Kontrollstrukturen aus Kapitel 4.

C) Strings als besondere Datenstruktur für Text

Ein String steht in Java für Text und kann als Folge einzelner Zeichen verstanden werden. Wie bei Arrays spielt die Position eine Rolle: Zeichen können über ihren Index betrachtet werden.

String kurs = "Informatik";

int laenge = kurs.length();
char erstesZeichen = kurs.charAt(0);
String kuerzer = kurs.substring(0, 5); // "Infor"

Strings sind für Text optimiert und bieten dafür eigene Operationen. Gleichzeitig bleiben sie strukturiert genug, um Zeichenfolgen systematisch zu durchlaufen.

// Iteration über alle Zeichen eines Strings
for (int i = 0; i < kurs.length(); i++) {
    System.out.println(kurs.charAt(i));
}

D) Gemeinsamkeiten von Arrays und Strings

  • Beide speichern mehrere Werte in einer geordneten Struktur.
  • Bei beiden erfolgt der Zugriff positionsbezogen über Indizes.
  • Beide können mit Schleifen vollständig durchlaufen werden (Iteration).
  • Beide bilden damit eine direkte Grundlage für algorithmische Verfahren.

Diese gemeinsame Strukturperspektive ist entscheidend: Lernende betrachten Arrays und Strings nicht als isolierte Einzelthemen, sondern als Varianten derselben Grundidee „strukturierte Daten“.

E) Einordnung: primitive Datentypen, komplexe Strukturen und Ausblick

Im Unterschied zu primitiven Datentypen wie int oder boolean, die jeweils einen einzelnen Wert speichern, repräsentieren Arrays und Strings mehrere, strukturierte Werte in einer gemeinsamen Form.

Für die nächsten Kapitel ist diese Einordnung zentral: Algorithmen in Kapitel 8 bis 10 arbeiten auf genau solchen Strukturen, etwa beim Suchen und Sortieren in Arrays. Zugleich ist der Blick nach vorne wichtig: Strings sind in Java Objekte, und komplexere Datenorganisation wird in der Qualifikationsphase systematisch über Objektstrukturen vertieft (siehe Q2.1).

Nächster Schritt: Damit ist die Datenbasis komplett – jetzt werden allgemeine Algorithmen formuliert, die auf diesen Strukturen arbeiten.

GUI und Ereignissteuerung
Grafische Benutzeroberflächen und ereignisgesteuerte Programmierung
Interaktion über Fenster, Eingaben und Aktionen

Übergang: Nach dem EVA-Einstieg mit Konsolenprogrammen folgt nun der Transfer: Grafische Benutzeroberflächen setzen dieselbe Grundidee um, aber unter Ereignissteuerung.

Leitidee

GUI = EVA unter Ereignissteuerung.

1. EVA in grafischen Benutzeroberflächen

Bei einer GUI arbeitet das Programm nicht mehr nur in einer festen linearen Reihenfolge. Stattdessen wartet es auf Ereignisse (z. B. Klicks) und führt dann gezielt Verarbeitungsschritte aus.

  • Eingabe: Textfelder und Benutzeraktionen liefern Daten oder lösen Ereignisse aus.
  • Verarbeitung: Funktionen beziehungsweise Event-Handler prüfen, berechnen oder interpretieren diese Daten.
  • Ausgabe: Labels, Meldungen und Anzeigen machen Ergebnisse sichtbar.

Wichtig: Ein Button ist keine direkte Dateneingabe. Er ist ein Auslöser, der ein Ereignis erzeugt und damit die Verarbeitung startet.

EVA in einer grafischen Benutzeroberfläche: Textfeld und Button als Eingabe, Funktion als Verarbeitung, Label als Ausgabe.
EVA im GUI-Kontext: Nutzendeingaben und Klickereignisse werden verarbeitet und in einer Anzeige ausgegeben.

2. Beispiel: Begrüßung mit Texteingabe

import tkinter as tk

def begruessen():
    name = eingabe_name.get().strip()
    if not name:
        name = "Gast"
    label_ausgabe.config(text=f"Hallo, {name}!")

fenster = tk.Tk()
fenster.title("Begrüßung")

eingabe_name = tk.Entry(fenster, width=20)
eingabe_name.pack(pady=4)

button = tk.Button(fenster, text="Begrüßen", command=begruessen)
button.pack(pady=4)

label_ausgabe = tk.Label(fenster, text="Bitte Namen eingeben.")
label_ausgabe.pack(pady=4)

fenster.mainloop()
  • Eingabe: Name im Textfeld, Klick auf den Button.
  • Verarbeitung: Event-Handler begruessen() liest und prüft die Eingabe.
  • Ausgabe: Das Label zeigt die Begrüßung an.

3. Beispiel: Addition zweier Zahlen

import tkinter as tk

def addiere():
    a = float(eingabe_a.get())
    b = float(eingabe_b.get())
    ergebnis = a + b
    label_summe.config(text=f"Summe: {ergebnis}")

fenster = tk.Tk()
fenster.title("Addition")

eingabe_a = tk.Entry(fenster, width=12)
eingabe_b = tk.Entry(fenster, width=12)
eingabe_a.pack(pady=2)
eingabe_b.pack(pady=2)

button = tk.Button(fenster, text="Addieren", command=addiere)
button.pack(pady=4)

label_summe = tk.Label(fenster, text="Noch kein Ergebnis.")
label_summe.pack(pady=4)

fenster.mainloop()
  • Eingabe: Zwei Zahlen im GUI und Klick auf „Addieren“.
  • Verarbeitung: Event-Handler addiere() konvertiert und berechnet.
  • Ausgabe: Das Label zeigt die Summe.

4. Beispiel: Alter prüfen mit Entscheidung

import tkinter as tk

def pruefe_alter():
    alter = int(eingabe_alter.get())
    if alter >= 18:
        text = "volljährig"
    else:
        text = "minderjährig"
    label_status.config(text=f"Status: {text}")

fenster = tk.Tk()
fenster.title("Altersprüfung")

eingabe_alter = tk.Entry(fenster, width=10)
eingabe_alter.pack(pady=4)

button = tk.Button(fenster, text="Prüfen", command=pruefe_alter)
button.pack(pady=4)

label_status = tk.Label(fenster, text="Bitte Alter eingeben.")
label_status.pack(pady=4)

fenster.mainloop()
  • Eingabe: Alter im Textfeld und Klick auf „Prüfen“.
  • Verarbeitung: Event-Handler mit if-Entscheidung.
  • Ausgabe: Das Label zeigt den Status an.

5. Was passiert beim Klick auf einen Button?

Beim Start der Anwendung werden GUI-Elemente erzeugt und ein Event-Handler mit dem Button verknüpft. Nach der Initialisierung wartet die Ereignisschleife (mainloop()) auf Aktionen. Erst beim Klick wird der verknüpfte Handler ausgeführt, verarbeitet die aktuellen Eingaben und aktualisiert die Ausgabe.

Damit bleibt die Leitidee aus dem EVA-Abschnitt erhalten: Eingabe und Ausgabe sind sichtbar in der Oberfläche, während die Verarbeitung in klar abgegrenzten Funktionen stattfindet.

Nächster Schritt: Im folgenden Kapitel werden diese Bausteine als allgemeine Algorithmen abstrahiert.

Algorithmen
Algorithmen
Problemlösungen als endliche Schrittfolgen modellieren und darstellen

A) Was ist ein Algorithmus?

Nach Variablen, Kontrollstrukturen, Methoden und Datenstrukturen folgt nun die übergeordnete Perspektive: Ein Algorithmus beschreibt, wie diese Bausteine gezielt zu einer Lösung zusammenspielen.

Ein Algorithmus ist eine zielgerichtete, endliche Schrittfolge zur Lösung eines Problems. Er beschreibt nicht nur ein Ergebnis, sondern den reproduzierbaren Weg dorthin.

Positionierung: Dieses Kapitel behandelt den allgemeinen Begriff Algorithmus; die nächsten Kapitel zeigen konkrete Klassen davon: Suchalgorithmen und Sortieralgorithmen.

B) Eigenschaften von Algorithmen

C) Darstellung von Algorithmen

Algorithmen können als Text, als Code oder als Struktogramm beschrieben werden. Text erklärt die Idee, Code macht sie ausführbar, Struktogramme machen die Ablaufstruktur sichtbar und schließen direkt an Kapitel 4 (Kontrollstrukturen) an.

D) Beispielalgorithmus: Minimum in einem Array bestimmen

Kurzbeschreibung: Das Array wird linear durchlaufen. Wird ein kleinerer Wert gefunden, ersetzt er das aktuelle Minimum.

int minimum(int[] werte) {
    int min = werte[0];
    for (int i = 1; i < werte.length; i++) {
        if (werte[i] < min) {
            min = werte[i];
        }
    }
    return min;
}
Struktogramm: Minimumsuche (linear)

Leselogik: Initialisiere ein Startminimum, durchlaufe alle weiteren Werte, aktualisiere bei kleinerem Fund und gib am Ende das Minimum zurück.

E) Bedeutung für die Informatik

Algorithmen verbinden Kontrollstrukturen (Ablaufsteuerung) mit Datenstrukturen (Datenbasis). Auf diesem Fundament bauen die nächsten Kapitel auf: erst Suchalgorithmen, dann Sortieralgorithmen und deren Effizienzvergleich.

Nächster Schritt: Zuerst wird gesucht (finden), danach sortiert (ordnen) – beide Verfahren arbeiten auf derselben Datenbasis.

Suchalgorithmen
Suchalgorithmen
Lineare und binäre Suche sowie Hashing im Effizienzvergleich

Übergang: Nach dem allgemeinen Algorithmusbegriff folgt jetzt die erste konkrete Anwendungsklasse: Suchalgorithmen.

1. Konzeptklärung: Suchen in strukturierten Daten

Suchen bedeutet: Prüfen, ob ein Suchschlüssel in einer Datenstruktur vorkommt und wo er liegt. Die Wahl des Suchalgorithmus hängt direkt von der Struktur der Daten ab.

2. Lineare Suche

Die lineare Suche durchläuft ein Array von vorne nach hinten. In jedem Schritt wird genau ein Element mit dem Suchschlüssel verglichen. Abbruch: bei Treffer oder am Ende des Arrays.

Array: [18, 7, 42, 13, 29, 5], Suche: 13
Schritt 1: 18 != 13
Schritt 2: 7  != 13
Schritt 3: 42 != 13
Schritt 4: 13 == 13  → Treffer

Was passiert hier? Der Suchbereich bleibt immer das ganze Restarray. Die Strategie ist einfach, funktioniert immer, braucht aber im ungünstigen Fall viele Vergleiche.

boolean linearSuche(int[] a, int schluessel) {
    int i = 0;
    while (i < a.length && a[i] != schluessel) {
        i++;
    }
    return i < a.length;
}
Struktogramm: Lineare Suche

Was zeigt dieses Struktogramm? Die Suche ist als Wiederholung mit integrierter Auswahl modelliert: prüfen, ggf. abbrechen, sonst weiterlaufen.

3. Binäre Suche

Die binäre Suche funktioniert nur bei sortierten Daten. Sie prüft die Mitte und halbiert danach den Suchbereich (links oder rechts). Das ist das Prinzip „Teile und herrsche“.

Sortiertes Array: [5, 7, 13, 18, 29, 42], Suche: 29
links=0, rechts=5, mitte=2 → 13 zu klein → rechten Teil nehmen
links=3, rechts=5, mitte=4 → 29 gefunden

Was passiert hier? Der Suchbereich wird in jedem Schritt kleiner. Dadurch sinkt die Zahl der Vergleiche deutlich gegenüber der linearen Suche.

boolean binaereSuche(int[] a, int schluessel) {
    int links = 0, rechts = a.length - 1;
    while (links <= rechts) {
        int mitte = (links + rechts) / 2;
        if (a[mitte] == schluessel) return true;
        if (a[mitte] < schluessel) links = mitte + 1;
        else rechts = mitte - 1;
    }
    return false;
}
Struktogramm: Binäre Suche

Was zeigt dieses Struktogramm? Die Entscheidungsstruktur halbiert den Suchraum systematisch: Treffer, rechts weitersuchen oder links weitersuchen.

4. Hashing

Hashing berechnet aus dem Suchschlüssel direkt eine Position in einer Hashtabelle, statt Schritt für Schritt zu vergleichen.

Hashfunktion: h(k) = k mod 13
k = 1849  → h(1849) = 3
k = 1862  → h(1862) = 3  (Kollision)

Was passiert hier? Zwei Schlüssel können auf denselben Index fallen (Kollision). Dann braucht man eine Kollisionsstrategie, z. B. lineares Verschieben zur nächsten freien Position im Array.

Struktogramm: Hashing (vereinfacht)

Was zeigt dieses Struktogramm? Hashing ersetzt viele Vergleiche durch eine direkte Indexberechnung und eine kurze Fallunterscheidung.

Begriff: Hashing und Kollision

Hashing ordnet Schlüssel per Berechnungsfunktion einem Index zu; eine Kollision liegt vor, wenn zwei Schlüssel denselben Index erzeugen.

5. Effizienzvergleich beim Suchen

Nicht Zahlen auswendig lernen, sondern Zusammenhänge verstehen: Struktur und Vorarbeit bestimmen die Suchgeschwindigkeit.

Nächster Schritt: Für die binäre Suche ist Sortierung eine zentrale Voraussetzung – daher folgt jetzt die zweite Anwendungsklasse: Sortieralgorithmen.

Sortieralgorithmen
Sortieralgorithmen
Selection, Insertion und Bubble Sort mit Effizienzvergleich

Übergang: Nach dem Finden folgt das Ordnen: Sortieralgorithmen strukturieren dieselben Daten, damit nachgelagerte Verarbeitung effizienter wird.

1. Konzeptklärung: Ordnung als algorithmisches Ziel

Sortieren erzeugt Ordnung. Diese Ordnung ist oft Voraussetzung für effiziente Suche, insbesondere für die binäre Suche. Leitidee: Erst sortieren, dann schneller suchen.

2. Selection Sort

In jedem Durchlauf wird das kleinste Element im unsortierten Teil gesucht und an den Anfang dieses Teilbereichs getauscht.

[18, 7, 42, 13, 29, 5]
1. kleinstes=5  → Tausch mit Position 0  → [5, 7, 42, 13, 29, 18]
2. kleinstes=7  → bleibt vorne            → [5, 7, 42, 13, 29, 18]
3. kleinstes=13 → Tausch mit Position 2  → [5, 7, 13, 42, 29, 18]

Was passiert hier? Links wächst der sortierte Teil, rechts schrumpft der unsortierte Teil.

Struktogramm: Selection Sort

Was zeigt dieses Struktogramm? Eine äußere Schleife fixiert die Grenze des sortierten Bereichs, die innere Schleife sucht jeweils das Minimum.

3. Insertion Sort

Insertion Sort nimmt nacheinander ein Element aus dem unsortierten Teil und fügt es an der passenden Stelle in den sortierten Teil ein – wie beim Sortieren von Spielkarten.

[18 | 7, 42, 13, 29, 5]
7 einsortieren  → [7, 18 | 42, 13, 29, 5]
42 einsortieren → [7, 18, 42 | 13, 29, 5]
13 einsortieren → [7, 13, 18, 42 | 29, 5]

Was passiert hier? Der sortierte Bereich wird schrittweise aufgebaut; Einfügen kann Verschiebungen verursachen.

Struktogramm: Insertion Sort

Was zeigt dieses Struktogramm? Das neue Element wird aufgenommen, nach links eingeordnet und der sortierte Bereich dadurch erweitert.

4. Bubble Sort

Bubble Sort vergleicht benachbarte Elemente und vertauscht sie bei falscher Reihenfolge. Dadurch „wandern“ große Elemente in jedem Durchlauf weiter nach hinten.

Start: [18, 7, 42, 13, 29, 5]
1. Durchlauf → [7, 18, 13, 29, 5, 42]
2. Durchlauf → [7, 13, 18, 5, 29, 42]
...

Was passiert hier? Nach jedem Durchlauf steht am rechten Rand mindestens ein Element an seiner Endposition.

Struktogramm: Bubble Sort

Was zeigt dieses Struktogramm? Zwei verschachtelte Schleifen steuern die wiederholten Nachbarvergleiche; falsche Reihenfolgen werden lokal getauscht.

5. Effizienz beim Sortieren

Verglichen werden vor allem Zahl der Vergleiche und Zahl der Vertauschungen/Verschiebungen:

Verzahnung als Denkmodell

Die fachliche Reihenfolge ist bewusst durchgängig: Daten strukturieren → darin suchen → durch Sortierung Suche effizienter machen. So werden Datenstruktur, Algorithmus und Effizienz als zusammenhängendes Modell sichtbar.

Erreicht: Die Lernlinie von Werten bis zu Algorithmen ist geschlossen; alle Kapitelbausteine greifen nun als ein gemeinsames Denkmodell ineinander.