©
DHBW Ravensburg · V2025-12-27
Links zu Vorlesungsmaterialien (Skript, Folien, Übungen) im Moodle-Kurs
Der Quellcode ist die in einer Programmiersprache geschriebene textuelle Repräsentation eines Programms. Entwickler nutzen den Quellcode, um Algorithmen und logische Anweisungen zu formulieren, die vom Computer interpretiert und ausgeführt werden. Der Quellcode enthält die gesamte Logik der Anwendung und dient als Basis für die Kompilation oder Interpretation durch das System. Gut strukturierter und verständlicher Quellcode ist essenziell, nicht nur für die aktuelle Entwicklung, sondern auch für zukünftige Wartung und Erweiterung des Programms. Dies erfordert klare Namenskonventionen, konsistente Formatierung und Kommentierung.
Der Programmierstil bezieht sich auf die Art und Weise, wie der Quellcode organisiert und geschrieben wird. Ein guter Programmierstil zielt darauf ab, die Lesbarkeit & Wartbarkeit des Codes zu verbessern. Dazu gehören der sinnvolle Einsatz von Einrückungen, eine klare und konsistente Benennung von Variablen und Funktionen sowie der Verzicht auf unnötige Komplexität. Ein konsistenter Programmierstil hilft dabei, Fehler zu vermeiden, und macht es anderen Entwicklern einfacher, den Code zu verstehen und daran weiterzuarbeiten. Der Stil variiert oft je nach Programmiersprache und Entwicklerumgebung, doch existieren allgemeine Richtlinien, die für alle Sprachen gelten.
Coding Conventions sind standardisierte Regeln für das Schreiben von Quellcode, welche die Lesbarkeit unabhängig vom individuellen Programmierstil verbessern. Sie erleichtern damit die Zusammenarbeit im Team und vereinfachen langfristig die Wartung des Codes. Wichtige Aspekte:
"Normaler" Python Code
CPython-Version
Console output (MacBook M4 Pro)
PyPy-Version
Console output (MacBook M4 Pro)
Testen ist ein Bestandteil der Softwareentwicklung, der sicherstellt, dass Programme erwartungsgemäß funktionieren und Fehler frühzeitig erkannt werden. Kontinuierliches Testen verbessert die Softwarequalität und erhöht die Stabilität. Testarten (Auswahl):
Automatisierung: Frameworks wie JUnit erleichtern das Schreiben & Automatisieren von Tests.
Das JRE bietet die Laufzeitumgebung, die erforderlich ist, um Java-Anwendungen auszuführen. Es umfasst die JVM, Bibliotheken und weitere Ressourcen, die Java plattformunabhängig machen. Kernkomponenten:
Das JDK ist eine Sammlung von Werkzeugen & Bibliotheken für die Entwicklung, Kompilierung und Ausführung von Java-Anwendungen. Es ist die Grundlage für alle Java-IDEs. Zentrale Bestandteile:
Versionierung: Seit Java 11 alle 6 Monate. Alle 2 Jahre gibt es eine LTS-Version. Aktuell: JDK 25
Distributionen: Offiziell von Oracle; Open-Source-Alternative: OpenJDK
Programmierparadigmen sind grundlegende Ansätze zur Strukturierung & Organisation von Code. Sie beeinflussen die Art und Weise, wie Entwickler Probleme lösen, Software entwerfen und implementieren.
Das imperative Programmieren ist ein Paradigma, das sich darauf konzentriert, wie ein Programm seine Aufgaben ausführt. Es beschreibt die Schritte, die zur Lösung eines Problems erforderlich sind, und legt fest, wie der Programmablauf gesteuert wird. In Java wird imperatives Programmieren häufig in Kombination mit Kontrollstrukturen wie Schleifen und Bedingungen verwendet.
Im deklarativen Programmieren wird beschrieben, was erreicht werden soll, ohne detailliert anzugeben, wie dies geschehen soll. Dieses Paradigma konzentriert sich auf die Verwendung von Ausdrücken und Bedingungen, um das gewünschte Ergebnis zu erzielen. In Java zeigt sich deklaratives Programmieren häufig in der Verwendung von API-Funktionen und Datenbankabfragen (z.B. mit SQL).
Funktionales Programmieren fokussiert sich auf die Anwendung und Komposition von Funktionen, wobei Zustandsveränderungen vermieden werden – fördert einen deklarativen Programmierstil.
Java: Implementiert durch Lambda-Ausdrücke,
höherwertige Funktionen, das Package java.util.function und die Stream-API
(z. B. Filtern, Transformieren, Reduzieren von Daten).
Das objektorientierte Programmieren ist ein Paradigma, das die Strukturierung von Code um Objekte herum fördert. Objekte sind Instanzen von Klassen, die Daten (Attribute) und Verhalten (Methoden) kapseln. OOP bietet Konzepte wie Vererbung, Polymorphismus & Kapselung, die eine bessere Wiederverwendbarkeit und Wartbarkeit des Codes ermöglichen.
Eine IDE die v. a. früher zahlreich verwendet wurde, heute abnehmende Beliebtheit.
Zunehmende Beliebtheit. Leichtgewichtiger Editor mit zahlreichen Extensions.
Über Jahre stetig hohe Beliebtheit. Großes (vorgegebenes) Ökosystem.
Wird im Programmentwurf verwendet!
Die main-Methode ist der Einstiegspunkt jedes Java-Programms und eine der wichtigsten Komponenten der Sprache. Sie wird von der JVM aufgerufen, um die Ausführung eines Programms zu starten.
public: Die Methode ist öffentlich, damit die JVM darauf zugreifen kann.static: Die Methode gehört zur Klasse selbst und nicht zu einer Instanz, da die
JVM beim Programmstart keine Objekte erzeugt und die Methode direkt aufrufen muss.void: Zeigt an, dass die main-Methode keinen Wert zurückgibt, sondern lediglich den
Programmstartpunkt definiert und anschließend die Kontrolle an die JVM übergibt.String[] args: Das Argument ist ein Array von Zeichenketten, das Befehlszeilenargumente
enthält. Können zur Laufzeit genutzt werden, um das Programm-Verhalten dynamisch zu beeinflussen.
java CommandLineExample Se7en
Je nach Betriebssystem, JDK-Version und Verzeichnis-Struktur können sich Command-Line-Befehle für Java unterscheiden.
Generell kann jedoch ein Java-Programm, dessen Klasse „Main“ heißt, mit java Main aufgerufen
werden. Liegt noch keine kompilierte Version vor, kann mit javac Main.java eine solche Datei erzeugt
werden, anschließend kann das Programm ausgeführt werden. Sollte das Programm in einem
Unterverzeichnis, z. B. „src“ liegen, sehen die Befehle wie folgt aus:
javac src/Main.java und
java -cp src Main
Zur Vereinfachung wird während der Vorlesung auf die Funktionen der IDEs gesetzt.
Primitive Datentypen bilden die grundlegenden Bausteine für die Verarbeitung von Daten in Java. Sie sind die einfachsten Datentypen und werden zur Darstellung grundlegender Informationen wie Zahlen, Zeichen und Wahrheitswerte verwendet. Im Gegensatz zu Objekten, sogenannten Referenztypen haben primitive Datentypen keine Methoden und sind nicht veränderbar – wird als immutable bezeichnet).
| Datentyp | Speichergröße | Wertebereich |
|---|---|---|
| byte | 8 Bits | -128 bis 127 |
| short | 16 Bits | -32.768 bis 32.767 |
| int | 32 Bits | -2.147.483.648 bis 2.147.483.647 |
| long | 64 Bits | -9.223.372.036.854.775.808 bis 9.223.372.036.854.775.807 |
| float | 32 Bits | ca. 1.4E-45 bis 3.4028235E+38 |
| double | 64 Bits | ca. 4.9E-324 bis 1.7976931348623157E+308 |
| char | 16 Bits | Unicode‑Zeichen (0 bis 65.535) |
| boolean | 1 Bit | true oder false |
Folgender Java-Code
Führt zu folgender Meldung in der Konsole
incompatible types: possible lossy conversion from long to int
Andere Beispiele
Lossy conversion
Möglich
Größere Datentypen sind möglich
Gegenmaßnahme (u.a.): Downcasting
Was ist hier zu erwarten?
Ergebnis
Gegenmaßnahmen (u.a.)
long, BigInteger)Kontrollstrukturen)
In Java ist der Datentyp String eine unveränderliche
(immutable) Klasse, die eine Folge von Zeichen repräsentiert und zur Speicherung und Manipulation
von Text verwendet wird. Der String-Typ bietet zahlreiche Methoden, um Operationen wie Verkettung,
Suche, Teilstring-Extraktion oder Vergleich durchzuführen.
| Operator | Beschreibung |
|---|---|
| + | Addition |
| - | Subtraktion |
| * | Multiplikation |
| / | Division |
| % | Modulo (Rest) |
JSON-Array mit Daten
Ausschnitt der Vue-Component
Warum tritt der Fehler auf?
Die Dezimalzahl 0.1306573 kann nicht exakt binär dargestellt werden.
Begründung: Es können nur Brüche dargestellt werden, die Summen von Potenzen sind (1/2, 1/4, 1/8, usw.).
Der Computer speichert stattdessen einen minimal ungenaueren Wert: 0.13065729999999998.
Dies ist eine direkte Folge der IEEE 754-Norm zur Darstellung von Fließkommazahlen.
Als Lösung für dieses Problem bieten Programmiersprachen wie Java z.B. eine BigDecimal-Klasse an.
| Operator | Beschreibung |
|---|---|
| == | Gleichheit |
| != | Ungleichheit |
| > | Größer als |
| < | Kleiner als |
| >= | Größer oder gleich |
| <= | Kleiner oder gleich |
| Operator | Beschreibung |
|---|---|
| && | Logisches UND |
| || | Logisches ODER |
| ! | Logische Negation |
| ^ | Logisches XOR |
| Operator | Beschreibung |
|---|---|
| & | Bitweise UND |
| | | Bitweise ODER |
| ~ | Bitweise Negation |
| ^ | Bitweise XOR |
| << | Signed Left Shift |
| >> | Signed Right Shift |
| >>> | Unsigned Right Shift |
Einsatzzwecke u.a. Embedded System, Kryptographie, mathematische Programme
| Operator | Beschreibung |
|---|---|
| = | Zuweisung |
| += | Addition und Zuweisung |
| -= | Subtraktion und Zuweisung |
| *= | Multiplikation und Zuweisung |
| /= | Division und Zuweisung |
| %= | Modulo und Zuweisung |
Die Inkrement- (++) & Dekrementoperatoren (--) erhöhen oder verringern den Wert einer Variablen um eins. Sie können sowohl vor der Variablen - präfix - als auch danach - postfix- verwendet werden.
Scanner-Klasse in Java dient zum Einlesen von
Benutzereingaben aus verschiedenen Quellen, u. a. der Konsole.
Sie bietet Methoden wie nextLine(), nextInt() oder nextDouble(),
um unterschiedliche Datentypen (z. B. Strings, Zahlen) einfach einzulesen und zu verarbeiten.
Die einfachste Form einer bedingten Verzweigung in Java ist die if-Anweisung.
Sie führt einen Codeblock nur dann aus, wenn die angegebene Bedingung erfüllt (true) ist.
Andernfalls wird der Codeblock übersprungen.
Die if-else-Verzweigung erweitert die if-Anweisung, indem sie eine Alternative bietet, wenn die Bedingung nicht wahr ist. Das bedeutet, dass ein alternativer Codeblock immer ausgeführt wird, wenn die Bedingung falsch ist.
Wenn mehrere Bedingungen nacheinander geprüft werden sollen, wird die if-else-if-Kette verwendet. Mit dieser Struktur können verschiedene Bedingungen nacheinander geprüft werden, und der erste Block, dessen Bedingung wahr ist, wird ausgeführt.
If-Else-Verzweigungen können auch verschachtelt werden, indem man if- oder if-else-Blöcke innerhalb anderer if- oder else-Blöcke platziert. Dies ermöglicht komplexere Entscheidungsstrukturen.
Java (und andere Programmiersprachen) bietet eine kompakte Möglichkeit, einfache If-Else-Verzweigungen mit dem ternären Operator in einer Zeile auszudrücken.
Die switch-Anweisung ist eine Kontrollstruktur
in Java, die es ermöglicht, eine Variable mit mehreren möglichen Werten zu vergleichen
und basierend auf dem Wert einen bestimmten Codeblock auszuführen. Sie wird häufig verwendet,
wenn mehrere Bedingungen nacheinander geprüft werden müssen und es zu umständlich oder
unübersichtlich wäre, viele if-else-if-Anweisungen zu verwenden.
switch-Anweisungen können zudem durch sogenannte jump tables
performanter sein, als if-else-Anweisungen (Paper-Link).
case: Jeder case-Block enthält einen möglichen Wert für den Ausdruck. Wenn der Ausdruck den
angegebenen Wert hat, werden die Anweisungen im entsprechenden case-Block ausgeführt.break: Beendet die switch-Anweisung, damit keine Anweisungen in den folgenden case-Blöcken
ausgeführt werden. Findet die break-Anweisung nicht statt, werden alle nachfolgenden case-Blöcke
ausgeführt - dieses Verhalten nennt man Fallthroughdefault: Wird ausgeführt, wenn keiner der vorherigen case-Blöcke zutrifft. Der default-Block ist optional.
Schleifen ermöglichen es, einen Block von Anweisungen wiederholt auszuführen, solange eine bestimmte Bedingung erfüllt ist. Java bietet mehrere Arten von Schleifen, die je nach Bedarf und Anwendungsfall verwendet werden können.
Die for-Schleife wird verwendet, wenn die Anzahl der Wiederholungen bereits im Voraus bekannt ist:
Die while-Schleife wird verwendet, wenn die Anzahl der Wiederholungen nicht im Voraus bekannt ist und die Schleife so lange laufen soll, wie eine bestimmte Bedingung wahr ist.
Die do-while-Schleife ist ähnlich wie die while-Schleife, führt jedoch den Anweisungsblock mindestens einmal aus, bevor die Bedingung überprüft wird.
Die erweiterte for-Schleife, for-each-Schleife genannt, ist eine Schleife, die speziell für die Iteration über Arrays & Sammlungen (engl. Collections) in Java entwickelt wurde. Sie ist besonders nützlich, wenn alle Elemente in einer Sammlung durchlaufen werden, ohne einen Index verwenden zu müssen.
break:
Beendet die Schleife sofort, unabhängig von der Bedingung.
continue:
Überspringt den aktuellen Durchlauf der Schleife und fährt mit dem nächsten Durchlauf fort.
Datenstrukturen sind essenzielle Werkzeuge in der Programmierung,
die es ermöglichen, Daten effizient zu speichern, zu organisieren und darauf
zuzugreifen. In Java gehören Arrays & ArrayLists
zu den grundlegendsten und am häufigsten verwendeten Datenstrukturen.
Ein Array ist eine Datenstruktur, die eine feste
Anzahl von Elementen desselben Typs enthält. Es wird zur Speicherung einer festgelegten
Anzahl von Werten verwendet, die über einen Index angesprochen werden können.
Java bietet Mechanismen, die primitive Datentypen automatisch in ihre entsprechenden Wrapper- Klassen zu konvertieren und umgekehrt.
Die ArrayList ist eine flexible, dynamische
Datenstruktur, die Teil der Java Collections Framework ist. Im Gegensatz zu Arrays kann ihre
Größe dynamisch angepasst werden, was sie für Anwendungen geeignet macht, bei denen die Anzahl
der zu speichernden Elemente nicht im Voraus bekannt ist.
new Random().nextInt(100)+1. Verwende eine
forEach-Schleife, um alle Zahlen in der Liste zu durchlaufen und nur die geraden Zahlen auszugeben.Ein Parameter ist eine Variable, die in der Methodensignatur definiert ist und der Methode einen Wert übergibt, wenn sie aufgerufen wird. Parameter ermöglichen es Methoden, Eingabewerte zu erhalten und basierend auf diesen Werten Operationen durchzuführen. Die Definition von Parametern erfolgt in der Methodensignatur, zwischen dem Methodennamen und den geschweiften Klammern.
Bei der Übergabe von Wertparametern wird eine Kopie des Wertes an die Methode übergeben. Änderungen am Parameter innerhalb der Methode haben keinen Einfluss auf den ursprünglichen Wert außerhalb der Methode.
Bei der Übergabe von Referenzparametern wird die Referenz (der Speicherort) eines Objekts an die Methode übergeben. Änderungen an den Parametern innerhalb der Methode wirken sich auf das ursprüngliche Objekt aus.
Demonstriere anhand eines einfachen Beispiels, wie Parameter in Java sowohl als Wert als auch als Referenz übergeben werden:
Java unterstützt auch die Verwendung von variablen Argumenten, sogenannten
Varargs, die es ermöglichen, eine beliebige
Anzahl von Argumenten eines bestimmten Typs an eine Methode zu übergeben. Dies ist besonders
nützlich, wenn die Anzahl der Eingaben zur Compile-Zeit nicht bekannt ist.
In Java sind Methoden grundlegende Bausteine, die es ermöglichen, Code zu strukturieren und wiederverwendbar zu gestalten. Methoden können in zwei Hauptkategorien unterteilt werden: Prozeduren & Funktionen.
void zeigt an, dass die Prozedur keine Werte
zurückgibt, sondern lediglich Aktionen ausführt.
return den berechneten Wert zurück.
Ein Referenzdatentyp ist ein Datentyp, der eine Referenz auf ein Objekt im Speicher hält, anstatt den Wert des Objekts selbst zu speichern – im Gegensatz zu primitiven Datentypen. Diese Referenz ermöglicht den Zugriff auf die Attribute und Methoden des Objekts.
Klassen: Grundlage für die Erstellung von Objekten in Java. Sie definieren die Struktur und das Verhalten von Objekten, einschließlich ihrer Attribute und Methoden.
Interface: Eine Sammlung von abstrakten Methoden, die von Klassen implementiert werden können. Interfaces fördern die Modularität und ermöglichen polymorphe Programmierung.
Arrays: Spezielle Objekte, die eine Sammlung von Werten des gleichen Datentyps speichern. In Java sind Arrays selbst Referenzdatentypen, die auf eine Gruppe von Werten verweisen.
Strings: Eine spezielle Art von Referenzdatentypen, die eine Zeichenfolgenstruktur repräsentieren.
Eine Nullreferenz eine Referenzvariable, die mit null
belegt ist und somit auf kein Objekt im Speicher verweist; der Zugriff auf Methoden oder
Attribute einer solchen Referenz löst eine NullPointerException aus, weshalb vor der Nutzung
stets eine Nullprüfung empfohlen wird.
Der instanceof-Operator wird verwendet, um zu
überprüfen, ob ein Objekt eine Instanz einer bestimmten Klasse oder eines Interfaces ist.
Dies wird in der objektorientierten Programmierung verwendet, um die
Typensicherheit zu gewährleisten.
Ein Enum (kurz für Enumerationen) ist eine spezielle
Klasse, die eine Gruppe von konstanten Werten definiert. In Java werden Enums mit dem
Schlüsselwort enum deklariert, gefolgt von einer
Liste der Werte, die durch Kommas getrennt sind.
Eine Klasse in Java ist ein Datentyp, der eine Sammlung von Attributen und Methoden innehält, um das Verhalten und die Eigenschaften von Objekten zu beschreiben. Klassen ermöglichen es Entwicklern, Daten und Funktionen logisch zu organisieren und wiederverwendbare Codeeinheiten zu erstellen.
In Java können Zugriffsmodifikatoren verwendet werden, um die Sichtbarkeit von Klassen, Attributen und Methoden zu steuern:
public:
Die Klasse, das Attribut oder die Methode ist von überall im Programm zugänglich.
private:
Die Klasse, das Attribut oder die Methode ist nur innerhalb der eigenen Klasse sichtbar.
protected:
Die Klasse, das Attribut oder die Methode ist innerhalb der eigenen Klasse, in abgeleiteten
Klassen und in Klassen im gleichen Paket sichtbar.
Ein Konstruktor ist eine spezielle Methode, die beim Erstellen eines Objekts einer Klasse aufgerufen wird. Konstruktoren haben denselben Namen wie die Klasse und haben keinen Rückgabewert. Sie werden verwendet, um die Attribute eines Objekts zu initialisieren.
Hinweis: Der Vorteil von this liegt in der Lösung von
Namenskonflikte zwischen Instanzvariablen & lokalen Variablen/ Parametern -
shadowing. this repräsentiert die Referenz auf das aktuelle Objekt.
Ein Objekt ist eine Instanz einer
Klasse, die im Speicher existiert und Zugriff auf die Attribute und Methoden der Klasse hat. Um ein
Objekt zu erstellen, d. h. zu instanziieren, verwendet man das
Schlüsselwort new, gefolgt von einem Aufruf des
Konstruktors der Klasse.
Mehrere Logik-Inhalte in einer Datei
Verteilung der Logiken in Subbausteine
Gründe gegen mehrere "lose" Klassen in einer Datei:
Person-Klasse, die zwei Felder enthält: name und age. Schreibe ein
Programm, das eine Person-Instanz erstellt und deren Name und Alter ausgibt.
Erstelle eine Klasse: Car. Verwende in beiden Klassen Konstruktoren und Zugriffsmodifikatoren:
brand, model und yearOfManufacture.
Vererbung ermöglicht es einer Klasse, die Eigenschaften und Methoden einer anderen Klasse zu erben, was zu einer Hierarchie von Klassen führt.
Method Overriding ist ein Konzept, bei dem eine abgeleitete Klasse
eine Methode einer Basisklasse mit der gleichen Signatur neu implementiert. Diese
Funktionalität ermöglicht es einer abgeleiteten Klasse, das Verhalten einer Methode der Basisklasse
zu ändern. Das Überschreiben einer Methode wird durch die Annotation
@Override gekennzeichnet.
circle, rectangle und triangle.Animal mit der Methode makeSound(). Leite
Klassen wie Dog und Cat ab, und überschreibe die Methode.
Das super-Keyword wird verwendet, um auf die Methoden und Attribute
der übergeordneten Klasse zuzugreifen.
Vehicle und davon abgeleitete Klassen
wie Car und Motorcycle erstellt werden.Vehicle mit Unterklassen Car und Bicycle. Implementiere unterschiedliche
Methoden wie driving() für jede Klasse.
Das static-Keyword wird verwendet, um Variablen und
Methoden als Klassenmitglieder zu deklarieren, die nicht
an eine spezifische Instanz einer Klasse gebunden sind. Stattdessen sind sie auf die Klasse selbst bezogen.
ShoppingBasket mit einer statischen Konstanten
MAX_ITEMS = 10. Füge eine statische Methode isFull(int currentAmount)
hinzu, die prüft, ob die Artikelanzahl den Maximalwert erreicht.
Teste die Methode mit verschiedenen Werten.AppConfiguration mit einer statischen Liste
defaultLanguages, die vordefinierte Sprachen (z.B. "Deutsch", "Englisch") enthält.
Schreibe eine statische Methode addLanguages(String language), die eine neue
Sprache zur Liste hinzufügt. Gib die Liste nach dem Hinzufügen aus.
final wird verwendet, um eine Variable, Methode/
Klasse als unveränderlich zu kennzeichnen – einmal zugewiesene Werte können
nicht geändert werden:
Finale Variablen: Eine finale Variable kann nur einmal zugewiesen und danach nicht mehr geändert werden.
Finale Methoden: Eine finale Methode kann nicht in einer abgeleiteten Klasse überschrieben werden.
Finale Klassen: Eine finale Klasse kann nicht erweitert (vererbt) werden.
calculateArea() implementiert werden, die den Flächeninhalt eines
Kreises berechnet. Die Methode nimmt den Radius als Parameter und berechnet die Fläche mit der
finalen PI-Variablen.Vehicle, die eine Methode driving() enthält, die mit dem final-Modifikator markiert
ist.Address mit den Attributen Street, town and postcode. Stelle
sicher, dass die Klasse unveränderlich bleibt.Getter & Setter sind spezielle Methoden in Java, die den Zugriff auf private Attribute einer Klasse ermöglichen. Sie fördern die Kapselung, welches die direkte Manipulation von Datenfeldern von außen verhindert. Der Zugriff auf die Werte dieser Attribute findet auf kontrollierte Weise statt.
get zu versehen.set zu versehen und hat als Parameter den
Wert, der zugewiesen werden soll.
Account, die das
aktuelle Guthaben speichert. Schreibe Getter- und Setter-Methoden mit Validierungen (z.B. keine
negativen Einzahlungen).Person mit privaten Attributen wie Name und Alter. Schreibe passende
Getter- und Setter-Methoden. Modifiziere die Setter-Methode so, dass sie das Alter auf Werte zwischen
0 und 120 begrenzt.
In Java ist Object die Wurzel der Klassenhierarchie.
Jede Klasse erbt direkt oder indirekt von Object. Daher verfügen alle Objekte
über grundlegende Methoden:
toString():
Gibt eine textuelle Darstellung des Objekts zurück. Für Logging und Debugging wird empfohlen,
diese Methode aussagekräftig zu überschreiben.equals(Object obj): Vergleicht zwei Objekte
auf inhaltliche Gleichheit. Die Standardimplementierung prüft nur die Referenzgleichheit
(wie der == Operator). Sie sollte überschrieben werden, um Felder zu vergleichen.hashCode(): Gibt einen Integer-Wert (Hash-Code)
für das Objekt zurück. Wenn equals() überschrieben wird, muss auch hashCode()
überschrieben werden, um sicherzustellen, dass gleiche Objekte denselben Hash-Code haben.
Wie ist Java hierarchisch aufgebaut?
Erstelle eine Klasse Soundtrack mit den Attributen title, artist und duration.
Überschreibe die Methoden toString(), equals() und hashCode() sinnvoll:
Erstelle zwei Musiktitel-Objekte mit denselben Attributen und prüfe, ob sie gleich sind
Records sind ein neuer Datentyp (ab Java 16). Sie bieten eine
einfache Möglichkeit, Datenklassen zu erstellen, die nur aus einem Satz von unveränderlichen
Attributen bestehen. Records reduzieren Boilerplate-Code, indem sie automatisch
Getter, toString(), equals() und hashCode()-Methoden
generieren. Ein Record wird mit dem Schlüsselwort record deklariert.
Point mit den Attributen x und y. Zeige, wie Records
mit equals(), hashCode() und toString() arbeiten.Book, der die Attribute title, author und pages enthält.
Implementiere eine Methode describeBook(), die eine kurze Beschreibung des Buches ausgibt.
Demonstriere in der main-Methode, wie du ein Buch-Objekt erstellst und die Methode aufrufst.
Eine abstrakte Klasse wird mit dem Schlüsselwort
abstract deklariert. Sie kann wie eine normale Klasse
Attribute und Methoden definieren, jedoch müssen nicht alle Methoden implementiert sein.
Abstrakte Methoden müssen in den abgeleiteten Klassen überschrieben werden. Zudem
kann eine abstrakte Klasse nicht instanziiert werden.
Shape mit Methoden wie calculateArea()
und calculatePerimeter(). Leite konkrete Klassen wie circle and
rectangle ab und implementiere die Methoden.Animal, die ein Attribut name enthält
und eine abstrakte Methode makeNoise(). Implementiere in der abstrakten Klasse eine
Methode showName(), die den Namen des Tieres ausgibt. Erstelle dann eine Klasse
Dog, die von der abstrakten Klasse Animal erbt und die Methode
makeNoise() implementiert. Demonstriere, wie du ein Hund-Objekt erstellst und beide
Methoden aufrufst.
Ein Interface ist ein abstrakter Datentyp, der eine Sammlung von
Definitionen zu Methoden & Konstanten beinhaltet. Die Deklaration findet mit dem Schlüsselwort
interface statt. Es ist möglich, dass eine
Klasse mehrere Interfaces implementiert. Eine Klasse, die ein Interface implementiert, muss
alle in diesem Interface deklarierten Methoden implementieren.
Seit Java 8 können Interfaces default-Methoden
enthalten, die eine Standardimplementierung bereitstellen.
Dies ermöglicht es, Interfaces zu erweitern, ohne bestehende Implementierungen zu beeinträchtigen.
Klassen, die das Interface implementieren, erben automatisch die
default-Methode, können sie aber bei Bedarf auch überschreiben.
Zeige den Unterschied zwischen abstrakten Klassen und Interfaces anhand eines Beispiels:
Vehicle, die ein Attribut brand enthält
und eine abstrakte Methode driving(). Implementiere in der abstrakten Klasse
eine Methode showBrand(), die den Wert des Attributs ausgibt. Erstelle
außerdem ein Interface EnergySource mit einer abstrakten Methode getEnergy(),
die den Energietyp eines Fahrzeugs zurückgibt (z. B. „Benzin“, „Elektrisch“).Car, die sowohl die abstrakte Klasse Vehicle
erweitert als auch das Interface EnergySource implementiert. Zeige anhand eines
Beispiels, wie die Methoden driving() und getEnergy() aufgerufen
werden. Erläutere dabei den Unterschied in der Verwendung von abstrakten Klassen und Interfaces.Method Overloading bei dem mehrere Methoden in derselben Klasse den gleichen Namen, jedoch unterschiedliche Parameterlisten haben. Dies ermöglichtes Entwicklern, die gleiche Methode für verschiedene Eingabetypen oder -anzahlen zu verwenden. Bei der Methodenüberladung unterscheidet sich die Signatur der Methoden durch eine der folgenden Eigenschaften:
Erstelle eine Klasse AppDate mit überladenen Methoden showDate(), die:
day, month und year als int-Variablen in der Reihenfolge Tag-Monat-Jahr ausgibt,month (String), day (int) und year (int) in der Reihenfolge Monat-Tag-Jahr ausgibt.
Erstelle eine Instanz von AppDate und rufe beide Methoden mit unterschiedlichen
Parametern auf, um die Überladung zu demonstrieren.
Kohäsion beschreibt die Beziehung innerhalb einer Klasse und misst, inwieweit die Methoden einer Klasse miteinander verbunden sind und zusammenarbeiten. Gründe für hohe Kohäsion:
Kopplung beschreibt die Beziehung zwischen Klassen und gibt die Stärke der Abhängigkeiten zwischen Programmeinheiten an. Eine hohe Kopplung bedeutet, dass Einheiten stark voneinander abhängig sind, während eine niedrige Kopplung Unabhängigkeit anzeigt. Gründe für niedrige Kopplung:
Polymorphismus ermöglicht, dass Objekte oder Methoden unterschiedliche Formen/Verhaltensweisen annehmen können, abhängig vom Kontext. Dies macht den Code erweiterbar & wiederverwendbar. Arten von Polymorphismus:
Upcasting ist die Umwandlung eines Objekts von einem Untertyp zu einem Obertyp. Dies geschieht in der Regel implizit und ist immer typsicher, da ein Objekt der Unterklasse immer auch eine Instanz der Oberklasse ist.
Downcasting ist die Umwandlung eines Objekts von einem Obertyp
zu einem Untertyp. Dies erfordert einen expliziten Cast und kann zur Laufzeit eine
ClassCastException auslösen, wenn das Objekt nicht
tatsächlich eine Instanz des Zieltyps ist. Daher sollte vorher mit
instanceof geprüft werden.
playSound(),
die je nach Typ eines Instruments (z. B. Gitarre, Klavier) unterschiedliche Sounds abspielt.MedicalDevice mit der Methode deviceInfo().
BloodPressureMonitor ab, die die Methode deviceInfo()
überschreibt und zusätzlich die Methode measure() enthält.BloodPressureMonitor und weise es einer Variablen vom Typ MedicalDevice zu (Upcasting).instanceof-Operator, ob das Objekt vom Typ BloodPressureMonitor ist.measure() auf.