Java-Grundlagen: Datentypen, Interfaces, Vererbung
Java-Grundlagen: Datentypen, Interfaces, Vererbung
Artikel-Übersicht
Diesen Artikel liest kaum jemand von vorn — man kommt her, weil man wissen will, wie % bei negativen Zahlen funktioniert oder wann ein Interface besser ist als eine abstrakte Klasse. Er ist deshalb als Nachschlagewerk gebaut: kurze, eigenständige Abschnitte mit knappem Codebeispiel. Was ihn von einem Tutorial unterscheidet, ist der letzte Satz jedes Abschnitts — die Entwurfsfolge. Was bedeutet dieses Sprachmittel für die Struktur, die man baut? Behandelt werden Datentypen und Operatoren, Klassen und Vererbung, Interfaces als der wichtigste Abschnitt des Artikels, Oberflächenprogrammierung und verteilte Aufrufe. Dazu eine ehrliche Antwort auf die Frage, ob Java noch zeitgemäß ist, und darauf, was Anfänger tatsächlich aufhält.
Wofür Java heute benutzt wird
Kurz und ohne Verteidigungshaltung: Unternehmensanwendungen aller Größenordnungen, Android, Datenverarbeitung im großen Maßstab, und eine erhebliche Menge an Infrastruktursoftware.
Ist Java noch zeitgemäß? Die Sprache hat sich seit Version 8 stärker verändert als in den fünfzehn Jahren davor. Dazugekommen sind unter anderem: Lambda-Ausdrücke und Streams, lokale Typableitung mit var, Records für unveränderliche Datenträger, Musterabgleich in switch, versiegelte Typen und virtuelle Threads für nebenläufige Programmierung ohne Thread-Pools.
Wer Java aus einer Vorlesung von 2012 kennt, kennt eine andere Sprache. Die Geschwätzigkeit ist geringer geworden, ohne dass die Berechenbarkeit gelitten hätte — und genau die ist der Grund, warum Java in großen, langlebigen Systemen so verbreitet ist.
Welche Version man dabei nimmt, behandle ich in Welche Java-Version? LTS, Distributionen und Migration.
Datentypen
Java unterscheidet primitive Typen und Referenztypen. Die primitiven:
| Typ | Größe | Wertebereich | Standardwert |
|---|---|---|---|
boolean |
JVM-abhängig | true / false |
false |
byte |
8 Bit | −128 … 127 | 0 |
short |
16 Bit | −32.768 … 32.767 | 0 |
char |
16 Bit | 0 … 65.535 (UTF-16-Einheit) | Nullzeichen (\u0000) |
int |
32 Bit | ca. −2,1 … 2,1 Mrd. | 0 |
long |
64 Bit | ca. ±9,2 Trillionen | 0L |
float |
32 Bit | Gleitkomma, ca. 7 Stellen | 0.0f |
double |
64 Bit | Gleitkomma, ca. 15 Stellen | 0.0d |
Zu jedem primitiven Typ gibt es eine Hüllklasse (Integer, Long, Double …), weil Sammlungen keine primitiven Typen aufnehmen können. Die automatische Umwandlung zwischen beiden — Autoboxing — ist bequem und hat zwei Fallen:
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b); // true — kleine Werte werden zwischengespeichert
System.out.println(c == d); // false — hier werden Referenzen verglichen!
Integer wert = null;
int primitiv = wert; // NullPointerException beim AuspackenImmer equals für Hüllklassen verwenden, nie ==.
Entwurfsfolge: float und double sind für Geldbeträge falsch. 0.1 + 0.2 ergibt nicht 0.3, und in einer Rechnungssumme fällt das irgendwann auf. Für Beträge nimmt man BigDecimal oder rechnet in der kleinsten Einheit mit long. Und statt int für eine Kundennummer lohnt ein eigener Typ — dann kann sie nicht mit einer Rechnungsnummer vertauscht werden. Warum solche Wertobjekte der lohnendste Baustein aus Domain-Driven Design sind, steht in Domain-Driven Design in der Praxis.
Operatoren, die Fragen aufwerfen
Modulo (%) liefert den Rest einer Division — und bei negativen Zahlen ein Ergebnis, das viele überrascht:
System.out.println( 7 % 3); // 1
System.out.println(-7 % 3); // -1 <- nicht 2!Java folgt hier der Division, nicht der mathematischen Modulo-Definition. Das Vorzeichen richtet sich nach dem Dividenden. Wer immer ein nicht negatives Ergebnis will, nutzt Math.floorMod(-7, 3) — das ergibt 2.
Das ist eine klassische Fehlerquelle bei Ringpuffern und Indexberechnungen.
^ ist XOR, nicht Potenzierung. Die häufigste Verwechslung überhaupt:
System.out.println(2 ^ 3); // 1 — bitweises XOR!
System.out.println(Math.pow(2, 3)); // 8.0 — so potenziert man2 ^ 3 rechnet 010 XOR 011 = 001. Wer eine Potenz will, nimmt Math.pow.
XOR ist trotzdem nützlich: a ^ b ^ b == a — deshalb steckt es in einfachen Prüfsummen und Verschlüsselungsverfahren. Und als logischer Operator auf boolean bedeutet es „genau eines von beiden".
Entwurfsfolge: Bitoperationen sind schnell und schwer zu lesen. In Fachlogik gehören sie nur mit Kommentar; wenn sie sich häufen, ist meist ein Aufzählungstyp die bessere Lösung.
Klassen, Objekte, Vererbung
Vererbung mit extends, der Aufruf des Oberklassenkonstruktors mit super:
class Rechnung {
protected final String nummer;
Rechnung(String nummer) {
this.nummer = nummer;
}
String beschreibung() { return "Rechnung " + nummer; }
}
class Storno extends Rechnung {
private final String grund;
Storno(String nummer, String grund) {
super(nummer); // muss die erste Anweisung sein
this.grund = grund;
}
@Override
String beschreibung() {
return super.beschreibung() + " (storniert: " + grund + ")";
}
}super hat zwei Bedeutungen: als Konstruktoraufruf und als Zugriff auf die überschriebene Methode der Oberklasse. Der Konstruktoraufruf muss die erste Anweisung sein — die Oberklasse muss vollständig aufgebaut sein, bevor die Unterklasse ihren Teil beiträgt.
Entwurfsfolge — und das ist der wichtigste Satz dieses Abschnitts: Tiefe Vererbungshierarchien sind ein Wartungsproblem. Wer die dritte Ebene erreicht, weiß beim Lesen einer Methode nicht mehr, wo das Verhalten herkommt. Die Alternative heißt Komposition: Statt von einer Klasse zu erben, hält man sie als Feld und delegiert. Das ist ausdrücklicher, leichter zu ändern und einzeln testbar. Wie das als Muster aussieht, steht in Factory, Adapter, Strategy, Visitor — Strategy ist genau die Antwort auf Vererbung, die eigentlich Verhaltensvariation sein wollte.
Interfaces
Der Abschnitt, nach dem am häufigsten gesucht wird.
Ein Interface beschreibt, was ein Typ können muss, ohne festzulegen, wie.
interface Zahlungsart {
Ergebnis belasten(Betrag betrag);
default boolean unterstuetztRueckerstattung() { // Standardimplementierung
return false;
}
static Zahlungsart standard() { // statische Methode
return new Lastschrift();
}
}Seit Java 8 dürfen Interfaces Standardmethoden haben, seit Java 9 auch private. Das verwischt die Grenze zur abstrakten Klasse — die es aber weiterhin gibt:
| Interface | Abstrakte Klasse | |
|---|---|---|
| Mehrfach implementierbar | ja | nein |
| Zustand (Felder) | nur Konstanten | ja |
| Konstruktor | nein | ja |
| Standardimplementierung | ja (default) |
ja |
| Sichtbarkeit der Methoden | öffentlich (oder privat) | frei |
| Gedacht für | „kann etwas" | „ist etwas" |
Die letzte Zeile ist die brauchbarste Merkregel. Ein Comparable ist keine Art von Ding, sondern eine Fähigkeit. Eine AbstractRechnung ist eine unvollständige Rechnung.
Warum es Standardmethoden gibt: Sie wurden eingeführt, um Interfaces nachträglich erweitern zu können, ohne alle bestehenden Implementierungen zu brechen. Das war notwendig, um Collection um Stream-Methoden zu ergänzen. Als Entwurfswerkzeug sind sie sparsam einzusetzen — ein Interface voller Standardimplementierungen ist eine abstrakte Klasse mit weniger Möglichkeiten.
Entwurfsfolge — der wichtigste Punkt des ganzen Artikels: Interfaces sind die Naht, an der Abhängigkeiten umgedreht werden. Wenn die Geschäftslogik ein Interface RechnungRepository definiert und die Datenbankschicht es implementiert, zeigt die Abhängigkeit nach innen statt nach außen. Genau das ist das technische Fundament von Clean Architecture — und der Grund, warum sich die Datenbank austauschen und die Fachlogik ohne Datenbank testen lässt.
Oberflächen: Swing und JavaFX
Kurz eingeordnet, weil danach oft gesucht wird:
Swing ist Teil des JDK, stammt aus den späten Neunzigern und funktioniert weiterhin. Ohne zusätzliche Abhängigkeit lauffähig, was es für Ausbildungsprojekte und kleine Werkzeuge praktisch macht. Modern sieht es nicht aus.
JavaFX ist der Nachfolger mit besserer Trennung von Aufbau und Gestaltung. Seit Java 11 ist es nicht mehr Teil des JDK und muss als eigene Abhängigkeit eingebunden werden — einige Distributionen liefern es mit, die meisten nicht.
Entwurfsfolge: Für neue Anwendungen ist die Oberflächenfrage heute meist eine Webfrage — das Gegenstück ist dann eine HTTP-Schnittstelle, wie in API-Design beschrieben. Desktop-Oberflächen in Java lohnen bei Werkzeugen ohne Netzanbindung, in stark regulierten Umgebungen und in der Ausbildung, weil sie ohne Serveraufbau auskommen.
Verteilte Aufrufe: RMI und was heute gilt
RMI erlaubt es, Methoden auf Objekten in einer anderen JVM aufzurufen, als wären sie lokal. Es ist Teil des JDK und war lange der Standardweg für verteilte Java-Anwendungen.
Für neue Systeme ist es keine Wahl mehr. Die Gründe: Es setzt Java auf beiden Seiten voraus, es ist über Firewalls hinweg unangenehm, und die Serialisierung ist eine bekannte Angriffsfläche.
Was heute stattdessen gilt: HTTP-Schnittstellen für synchrone Aufrufe, Nachrichten für asynchrone Verarbeitung. Beides sprachneutral, gut zu betreiben und zu überwachen.
Entwurfsfolge: Die Idee, entfernte Aufrufe wie lokale aussehen zu lassen, ist die eigentliche Falle — sie verdeckt, dass ein Netzwerkaufruf langsam sein, fehlschlagen und doppelt ankommen kann. Wer verteilt entwickelt, sollte die Grenze sichtbar halten. Warum Idempotenz dabei Pflicht ist, steht in Microservices bauen.
Ist Java schwer zu lernen?
Die Sprache selbst ist geschwätzig, aber berechenbar — es gibt wenige Überraschungen, und der Übersetzer meldet vieles früh.
Was Anfänger tatsächlich aufhält, ist nicht die Sprache, sondern die Werkzeugkette:
- Der Klassenpfad. Warum findet er meine Klasse nicht?
- Das Bauwerkzeug. Wozu Maven, was ist eine
pom.xml, warum lädt es Dinge herunter? - Die Projektstruktur. Warum
src/main/java, und warum muss der Paketname zum Ordner passen? - Mehrere JDKs auf einem Rechner. Welches nimmt jetzt was?
Das sind vier Themen, die mit Programmieren nichts zu tun haben und die vor der ersten interessanten Zeile stehen. Genau deshalb sind reduzierte Lernumgebungen am Anfang sinnvoll — sie blenden das aus. Und genau deshalb ist der Wechsel auf eine vollwertige Umgebung ein eigenes Lernthema, wie in Java-Editoren und IDEs beschrieben.
Häufige Fragen
Was programmiert man mit Java? Unternehmensanwendungen, Android-Apps, Datenverarbeitung und einen erheblichen Teil der Infrastruktursoftware.
Ist Java noch zeitgemäß? Ja. Die Sprache hat sich seit Version 8 stark verändert — Lambdas, Records, Musterabgleich, virtuelle Threads. Wer Java aus einer Vorlesung von 2012 kennt, kennt eine andere Sprache.
Ist Java schwer zu lernen? Die Sprache nicht besonders. Die Werkzeugkette — Klassenpfad, Bauwerkzeug, Projektstruktur — ist die eigentliche Hürde.
Was ist der Unterschied zwischen Interface und abstrakter Klasse? Ein Interface beschreibt eine Fähigkeit und ist mehrfach implementierbar. Eine abstrakte Klasse beschreibt eine unvollständige Art von Ding, kann Zustand halten und hat einen Konstruktor.
Wofür braucht man super?
Für den Aufruf des Oberklassenkonstruktors — als erste Anweisung — und für den Zugriff auf die überschriebene Methode der Oberklasse.
Warum ist -7 % 3 gleich -1?
Weil sich das Vorzeichen in Java nach dem Dividenden richtet. Für ein immer nicht negatives Ergebnis nimmt man Math.floorMod.
Ist ^ eine Potenz?
Nein, ^ ist bitweises XOR. Potenzieren geht mit Math.pow.
Zusammenfassung und praktische Tipps
Sprachgrundlagen sind schnell gelernt; die Entwurfsfolgen daraus sind das eigentlich Interessante. Die wichtigsten Punkte:
floatunddoublesind für Geldbeträge falsch.BigDecimaloder die kleinste Einheit alslong.- Hüllklassen immer mit
equalsvergleichen, nie mit==. %folgt dem Vorzeichen des Dividenden,Math.floorModliefert immer nicht negativ.^ist XOR, nicht Potenz.- Komposition schlägt tiefe Vererbung — spätestens ab der dritten Ebene.
- Interfaces sind die Naht für die Abhängigkeitsumkehr und damit das Fundament austauschbarer Infrastruktur.
- JavaFX ist seit Java 11 nicht mehr Teil des JDK.
- Was Anfänger aufhält, ist die Werkzeugkette, nicht die Sprache.
Mein Rat für den Einstieg: Nimm dir nach den ersten Wochen einen Nachmittag für die Werkzeugkette allein — Klassenpfad, Bauwerkzeug, Projektstruktur, ohne eine Zeile Fachlogik. Dieser Nachmittag erspart dir Monate an unverstandenen Fehlermeldungen. Es ist der am schlechtesten dokumentierte und am häufigsten übersprungene Teil des Java-Einstiegs.
Ressourcen
- Java Language Specification – die verbindliche Referenz zur Sprache
- Java API-Dokumentation – Klassenbibliothek je Version
- Java Version Almanac – welches Sprachmittel kam in welcher Version