Java ist eine der meistgenutzten Programmiersprachen der Welt – und das seit über 30 Jahren. Ob in Unternehmensanwendungen, Android-Apps, Backend-Systemen oder wissenschaftlichen Tools: Java ist überall. Dieser Artikel führt dich Schritt für Schritt durch die wichtigsten Grundlagen der objektorientierten Programmierung mit Java – verständlich, praxisnah und direkt anwendbar.
Warum Java auch 2026 noch relevant ist
Trotz moderner Alternativen wie Kotlin, Go oder Rust bleibt Java eine der gefragtesten Sprachen auf dem Jobmarkt. Der Grund: Millionen von bestehenden Systemen – in Banken, Behörden, E-Commerce und Industrie – laufen auf Java. Das JDK (Java Development Kit) erscheint regelmäßig mit neuen Features, zuletzt mit modernen Syntaxverbesserungen wie Records, Pattern Matching und Sealed Classes.
Java ist außerdem plattformunabhängig: Code, der einmal kompiliert wurde, läuft auf jeder Plattform, auf der eine JVM installiert ist. Dieses Prinzip – „Write once, run anywhere" – war vor Jahrzehnten revolutionär und ist heute noch ein echter Vorteil in heterogenen IT-Landschaften.
JDK, JRE und JVM – was ist was?
Drei Begriffe begegnen dir sofort, wenn du mit Java anfängst. Hier die klare Unterscheidung:
- JVM (Java Virtual Machine): Die Laufzeitumgebung, die deinen kompilierten Java-Bytecode ausführt. Die JVM ist plattformspezifisch – für Windows, Linux, macOS gibt es jeweils eine eigene Implementierung.
- JRE (Java Runtime Environment): Enthält die JVM plus Standardbibliotheken. Damit kannst du Java-Programme ausführen, aber nicht entwickeln.
- JDK (Java Development Kit): Das vollständige Paket für Entwickler – enthält JRE, Compiler (
javac), Debugger und weitere Tools.
Als Entwickler installierst du immer das JDK. Eine gute Wahl ist das kostenlose Eclipse Temurin (früher AdoptOpenJDK) oder das offizielle Oracle JDK.
Datentypen und Variablen
Java ist eine statisch typisierte Sprache – jede Variable hat einen festen Typ, der zur Kompilierzeit bekannt sein muss. Die primitiven Datentypen sind:
int alter = 25;
double preis = 9.99;
boolean aktiv = true;
char buchstabe = 'A';
long grosseZahl = 9_000_000_000L;
Daneben gibt es Referenztypen wie String, Arrays und alle selbst definierten Klassen. Ein String ist in Java kein primitiver Typ, sondern ein Objekt – was unter anderem bedeutet, dass du Strings mit .equals() vergleichst, nicht mit ==.
Seit Java 10 kannst du var für lokale Variablen verwenden, wenn der Typ eindeutig aus dem Kontext hervorgeht:
var name = "Arthur"; // Typ wird als String inferiert
var liste = new ArrayList<String>();
Kontrollfluss: if, for, while, switch
Die Kontrollstrukturen in Java kennst du wahrscheinlich aus anderen Sprachen. Hier ein kurzer Überblick:
// if/else
if (alter >= 18) {
System.out.println("Volljährig");
} else {
System.out.println("Minderjährig");
}
// for-Schleife
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// enhanced for (for-each)
String[] sprachen = {"Java", "Python", "Kotlin"};
for (String s : sprachen) {
System.out.println(s);
}
// switch (modern, seit Java 14+)
String tag = "Montag";
String typ = switch (tag) {
case "Samstag", "Sonntag" -> "Wochenende";
default -> "Werktag";
};
Der moderne Switch-Ausdruck ist kompakter und vermeidet vergessene break-Statements – ein häufiger Fehlerquell im klassischen Java.
Methoden und Überladen
Methoden sind das Herzstück der Java-Programmierung. Du definierst sie mit Rückgabetyp, Name und Parameterliste:
public int addiere(int a, int b) {
return a + b;
}
// Überladen: gleicher Name, andere Parameter
public double addiere(double a, double b) {
return a + b;
}
Method Overloading (Überladen) erlaubt es, denselben Methodennamen für verschiedene Parametertypen zu verwenden. Der Compiler wählt zur Kompilierzeit die passende Version – das ist bequem und gut lesbar.
Klassen und Objekte – OOP in Java
Java ist von Grund auf objektorientiert. Alles dreht sich um Klassen und deren Instanzen (Objekte).
public class Auto {
private String marke;
private int baujahr;
public Auto(String marke, int baujahr) {
this.marke = marke;
this.baujahr = baujahr;
}
public String getMarke() { return marke; }
public int getBaujahr() { return baujahr; }
public String toString() {
return marke + " (" + baujahr + ")";
}
}
// Verwendung
Auto meinAuto = new Auto("Toyota", 2023);
System.out.println(meinAuto); // Toyota (2023)
Die vier Grundprinzipien der OOP sind Kapselung (private Felder, public Getter/Setter), Vererbung, Polymorphismus und Abstraktion.
Vererbung und Polymorphismus
Mit extends erbt eine Klasse alle Felder und Methoden der Elternklasse:
public class Elektroauto extends Auto {
private int reichweiteKm;
public Elektroauto(String marke, int baujahr, int reichweite) {
super(marke, baujahr);
this.reichweiteKm = reichweite;
}
@Override
public String toString() {
return super.toString() + " | Reichweite: " + reichweiteKm + " km";
}
}
Polymorphismus bedeutet: Ein Elektroauto-Objekt kann überall dort verwendet werden, wo ein Auto erwartet wird – das ist das Fundament flexibler Softwarearchitektur.
Interfaces und abstrakte Klassen
Interfaces definieren einen Vertrag – Methoden, die eine Klasse implementieren muss. Seit Java 8 können Interfaces auch default-Methoden mit Implementierung enthalten:
public interface Fahrbar {
void fahren(int km);
default void hupen() {
System.out.println("Beep!");
}
}
Abstrakte Klassen liegen zwischen Interface und konkreter Klasse: Sie können teilweise implementierte Methoden enthalten, aber nicht direkt instanziiert werden. Nutze abstrakte Klassen, wenn du gemeinsame Logik zwischen verwandten Klassen teilen möchtest.
Ausnahmebehandlung
Fehler werden in Java als Exceptions behandelt. Mit try/catch/finally fängst du sie ab:
try {
int ergebnis = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Fehler: " + e.getMessage());
} finally {
System.out.println("Wird immer ausgeführt");
}
Unterscheide zwischen checked Exceptions (müssen behandelt oder deklariert werden, z.B. IOException) und unchecked Exceptions (RuntimeExceptions, z.B. NullPointerException). Gute Praxis: Fange nur Exceptions, die du sinnvoll behandeln kannst – logge und re-throwe alle anderen.
Collections: ArrayList und HashMap
Das Java Collections Framework bietet mächtige Datenstrukturen:
// ArrayList – dynamisches Array
List<String> namen = new ArrayList<>();
namen.add("Alice");
namen.add("Bob");
namen.remove("Alice");
System.out.println(namen.size()); // 1
// HashMap – Schlüssel-Wert-Paare
Map<String, Integer> punkte = new HashMap<>();
punkte.put("Alice", 95);
punkte.put("Bob", 87);
System.out.println(punkte.get("Alice")); // 95
Weitere wichtige Collections: LinkedList, HashSet (keine Duplikate), TreeMap (sortiert). Programmiere immer gegen das Interface (List, Map, Set), nicht gegen die konkrete Implementierung – das erleichtert spätere Änderungen.
Streams und Lambdas (funktionale Programmierung)
Seit Java 8 kannst du Collections funktional verarbeiten – kompakt und lesbar:
List<Integer> zahlen = List.of(1, 2, 3, 4, 5, 6);
int summeGerader = zahlen.stream()
.filter(n -> n % 2 == 0) // nur gerade
.mapToInt(Integer::intValue) // zu int konvertieren
.sum(); // summieren
System.out.println(summeGerader); // 12
Lambdas sind anonyme Funktionen, die du als Parameter übergibst. Streams verarbeiten Daten in einer Pipeline ohne die ursprüngliche Collection zu verändern. Diese funktionale Denkweise macht Java-Code deutlich kürzer und ausdrucksstärker.
Build-Tools: Maven und Gradle
Für professionelle Java-Projekte brauchst du ein Build-Tool. Die zwei wichtigsten sind:
- Maven: XML-basiert (
pom.xml), sehr weit verbreitet in Enterprise-Projekten, striktes Konventionsprinzip (Convention over Configuration). - Gradle: Groovy/Kotlin-basiert (
build.gradle), flexibler und schneller als Maven, Standard bei Android-Projekten.
Beide Tools verwalten Abhängigkeiten (Dependencies), führen Tests aus und paketieren deine Anwendung. Ein Maven-Projekt hat immer dieselbe Struktur: src/main/java für Quellcode, src/test/java für Tests.
Für den Einstieg in Webentwicklung mit Java ist Spring Boot der De-facto-Standard: Mit wenigen Zeilen Code hast du einen vollständigen REST-Server laufen – inklusive Dependency Injection, Datenbankanbindung und Security. Eine Einführung in REST-APIs findest du in unserem REST-Artikel.
Java vs. Kotlin – wann welche Sprache?
Kotlin ist Javas moderner Nachfolger auf der JVM – vollständig interoperabel mit Java-Code. Kotlin überzeugt durch kürzere Syntax, Null-Safety und Coroutines für asynchrone Programmierung. Für neue Android-Apps ist Kotlin heute die erste Wahl. Für bestehende Enterprise-Systeme, große Teams und maximale Tooling-Unterstützung bleibt Java jedoch unschlagbar. Beide Sprachen laufen auf derselben JVM – du kannst sie sogar im selben Projekt mischen.
Lerne Java als Grundlage – der Wechsel zu Kotlin ist danach sehr einfach. Versionskontrolle mit Git und eine gute IDE wie VS Code oder IntelliJ IDEA sind unabhängig von der Sprache essenziell.
Häufige Fragen
Muss ich Java lernen, wenn Kotlin moderner ist?
Nicht zwingend – aber es hilft. Java und Kotlin teilen die JVM und viele Konzepte. Wer Java versteht, lernt Kotlin in wenigen Wochen. Außerdem ist Java in vielen bestehenden Codebasen Standard, sodass du als Java-Entwickler sofort produktiv bist.
Welche Java-Version soll ich verwenden?
Verwende immer die aktuelle LTS-Version (Long-Term Support). Stand 2026 ist das Java 21. LTS-Versionen werden mehrere Jahre mit Sicherheitsupdates versorgt – ideal für produktive Projekte.
Ist Java wirklich langsam?
Das ist ein veraltetes Vorurteil. Die moderne JVM mit JIT-Kompilierung (Just-In-Time) macht Java-Programme sehr schnell. Für die meisten Anwendungen ist Java performant genug – und deutlich schneller als Python oder Ruby in rechenintensiven Aufgaben.
Wie starte ich am besten mit Java?
Installiere das JDK, richte IntelliJ IDEA Community (kostenlos) oder VS Code mit Java-Extension ein und schreibe dein erstes „Hello World". Dann arbeite dich durch die Grundlagen: Variablen, Schleifen, Klassen, Collections. Lege danach ein erstes kleines Maven-Projekt an und entdecke Spring Boot.
Wie unterscheiden sich checked und unchecked Exceptions?
Checked Exceptions (z.B. IOException) muss der Compiler behandeln – du musst sie entweder mit try/catch abfangen oder in der Methodensignatur mit throws deklarieren. Unchecked Exceptions (RuntimeExceptions wie NullPointerException) können überall auftreten und müssen nicht explizit behandelt werden – es empfiehlt sich aber, sie durch defensiven Code zu vermeiden.