Direkt zum Inhalt

OOP in Java: Klassen, Objekte, Kapselung, Vererbung und Abstraktion

Lerne objektorientiertes Programmieren in Java mit praktischen Beispielen. Meisterklassen, Objekte, Vererbung, Kapselung und abstrakte Klassen anhand eines Restaurant-Menüsystems.
Aktualisierte 14. Feb. 2025  · 15 Min. Lesezeit

Java ist durchgehend eine der drei beliebtesten Sprachen der Welt. Seine Verbreitung in Bereichen wie der Entwicklung von Unternehmenssoftware, mobilen Android-Apps und groß angelegten Webanwendungen ist unübertroffen. Sein starkes Typensystem, sein umfangreiches Ökosystem und seine "write once, run anywhere"-Fähigkeit machen es besonders attraktiv für den Aufbau robuster, skalierbarer Systeme. In diesem Artikel werden wir untersuchen, wie die objektorientierten Programmierfunktionen von Java es Entwicklern ermöglichen, diese Fähigkeiten effektiv zu nutzen und durch die richtige Organisation und Wiederverwendung von Code wartbare und skalierbare Anwendungen zu erstellen.

Ein Hinweis zum Organisieren und Ausführen von Java-Code

Bevor wir mit dem Schreiben von Code beginnen, sollten wir einige Einstellungen vornehmen.

Wie bei der Syntax gibt es auch bei Java strenge Regeln für die Codeorganisation.

Zunächst muss jede öffentliche Klasse in einer eigenen Datei stehen, die genau wie die Klasse benannt ist, aber die Erweiterung.java hat. Wenn ich also eine Laptop-Klasse schreiben will, muss der Dateiname Laptop.java- lauten , wobei Groß- und Kleinschreibung zu beachten sind. Du kannst nicht-öffentliche Klassen in der gleichen Datei haben, aber es ist am besten, sie zu trennen. Ich weiß, dass wir zu weit vorpreschen und über die Organisation von Klassen sprechen, noch bevor wir sie schreiben, aber es ist eine gute Idee, sich vorher eine grobe Vorstellung davon zu machen, wo man die Dinge unterbringen will.

Alle Java-Projekte müssen eine Main.java Datei mit der KlasseMain haben . Hier testest du deine Klassen, indem du aus ihnen Objekte erstellst.

Um Java-Code auszuführen, verwenden wir IntelliJ IDEA, eine beliebte Java-IDE. Nach der Installation von IntelliJ:

  1. Erstelle ein neues Java-Projekt (Datei > Neu > Projekt)
  2. Klicken Sie mit der rechten Maustaste auf den Ordner src, um die Main.java Datei und füge den folgenden Inhalt ein:
public class Main {
   public static void main(String[] args) {
       // Create and tests objects here
      
   }
}

Wenn es um Klassen geht, schreiben wir den Code in andere Dateien als die Main.java Datei. Wenn es aber um das Erstellen und Testen von Objekten geht, wechseln wir zu Main.java.

Um das Programm zu starten, klickst du auf den grünen Play-Button neben der Hauptmethode:

Ein Screenshot eines Editorfensters in IntelliJ IDEA for Java

Die Ausgabe wird unten im Fenster des Ausführungswerkzeugs angezeigt.

Wenn du ganz neu in Java bist, schau dir unseren Kurs Einführung in Javader die Grundlagen der Java-Datentypen und des Kontrollflusses behandelt, bevor du fortfährst.

Ansonsten lass uns gleich loslegen.

Java-Klassen und -Objekte

Was genau sind also Klassen?

Klassen sind Programmierkonstrukte in Java zur Darstellung von Konzepten aus der realen Welt. Betrachte zum Beispiel diese MenuItem-Klasse (erstelle eine Datei, um diese Klasse in deiner IDE zu schreiben):

public class MenuItem {
   public String name;
   public double price;
}

Die Klasse gibt uns eine Blaupause oder eine Vorlage, um verschiedene Menüpunkte in einem Restaurant darzustellen. Indem wir die beiden Attribute der Klasse name und price ändern, können wir unzählige Menüobjekte wie einen Burger oder einen Salat erstellen .

Um also eine Klasse in Java zu erstellen, beginnst du mit einer Zeile, die die Zugriffsebene der Klasse beschreibt (private,public oder protected), gefolgt von dem Klassennamen. Unmittelbar nach der Klammer umreißt du die Eigenschaften deiner Klasse.

Aber wie erstellen wir Objekte, die zu dieser Klasse gehören? Java ermöglicht dies durch Konstruktormethoden:

public class MenuItem {
   public String name;
   public double price;
  
   // Constructor
   public MenuItem(String name, double price) {
       this.name = name;
       this.price = price;
   }
}

Ein Konstruktor ist eine spezielle Methode, die aufgerufen wird, wenn wir ein neues Objekt aus einer Klasse erstellen. Sie initialisiert die Attribute des Objekts mit den von uns angegebenen Werten. Im obigen Beispiel nimmt der Konstruktor einen Namen und einen Preis als Parameter und weist sie den Feldern des Objekts zu.

Die Syntax für den Konstruktor unterscheidet sich von anderen Klassenmethoden, da du keinen Rückgabetyp angeben musst. Außerdem muss der Konstruktor denselben Namen wie die Klasse haben und er sollte dieselbe Anzahl von Attributen haben, die du nach der Klassendefinition deklariert hast. Oben hat der Konstruktor zwei Attribute erstellt, weil wir zwei nach der Klassendefinition deklariert haben: name und price.

Nachdem du deine Klasse und ihren Konstruktor geschrieben hast, kannst du in deiner Hauptmethode Instanzen (Objekte) von ihr erstellen:

public class Main {
   public static void main(String[] args) {
       // Create objects here
       MenuItem burger = new MenuItem("Burger", 3.5);
       MenuItem salad = new MenuItem("Salad", 2.5);
       System.out.println(burger.name + ", " + burger.price);
   }
}

Ausgabe:

Burger, 3.5

Oben haben wir zwei MenuItem Objekte in den Variablen burger und saladerstellt . Wie in Java erforderlich, muss der Typ der Variablen deklariert werden, der MenuItem ist. Um eine Instanz unserer Klasse zu erstellen, schreiben wir das Schlüsselwort new und rufen anschließend die Konstruktormethode auf.

Neben dem Konstruktor kannst du auch reguläre Methoden erstellen, die deiner Klasse ein Verhalten verleihen. Unten fügen wir zum Beispiel eine Methode hinzu, um den Gesamtpreis nach Steuern zu berechnen:

public class MenuItem {
   public String name;
   public double price;
  
   // Constructor
   public MenuItem(String name, double price) {
       this.name = name;
       this.price = price;
   }
  
   // Method to calculate price after tax
   public double getPriceAfterTax() {
       double taxRate = 0.08; // 8% tax rate
       return price + (price * taxRate);
   }
}

Jetzt können wir den Gesamtpreis inklusive Steuern berechnen:

public class Main {
   public static void main(String[] args) {
       MenuItem burger = new MenuItem("Burger", 3.5);
       System.out.println("Price after tax: $" + burger.getPriceAfterTax());
   }
}

Ausgabe:

Price after tax: $3.78

Verkapselung

Der Zweck von Klassen ist es, einen Bauplan für die Erstellung von Objekten zu erstellen. Diese Objekte können dann von anderen Skripten oder Programmen verwendet werden. Unsere MenuItem Objekte können zum Beispiel von einer Benutzeroberfläche verwendet werden, die ihren Namen, ihren Preis und ihr Bild auf einem Bildschirm anzeigt.

Aus diesem Grund müssen wir unsere Klassen so gestalten, dass ihre Instanzen nur so verwendet werden können, wie wir es beabsichtigt haben. Im Moment ist unsere MenuItem Klasse sehr einfach und fehleranfällig. Eine Person könnte Objekte mit lächerlichen Eigenschaften erschaffen, wie z.B. einen Apfelkuchen zu einem schlechten Preis oder ein Sandwich für eine Million Dollar:

// Inside Main.java
MenuItem applePie = new MenuItem("Apple Pie", -5.99);  // Negative price!
MenuItem sandwich = new MenuItem("Sandwich", 1000000); // Unreasonably expensive

System.out.println("Apple pie price: $" + applePie.price);
System.out.println("Sandwich price: $" + sandwich.price);

Nachdem du also eine Klasse geschrieben hast, musst du zunächst ihre Attribute schützen, indem du ihre Erstellung und den Zugriff darauf einschränkst. Zunächst wollen wir nur positive Werte für den Preis zulassen und einen Maximalwert festlegen, damit nicht versehentlich lächerlich teure Artikel angezeigt werden.

In Java können wir dies mit Hilfe von Setter-Methoden erreichen:

public class MenuItem {
   private String name;
   private double price;
   private static final double MAX_PRICE = 100.0;
  
   public MenuItem(String name, double price) {
       this.name = name;
       setPrice(price);
   }
  
   public void setPrice(double price) {
       if (price < 0) {
           throw new IllegalArgumentException("Price cannot be negative");
       }
       if (price > MAX_PRICE) {
           throw new IllegalArgumentException("Price cannot exceed $" + MAX_PRICE);
       }
       this.price = price;
   }
  
}

Schauen wir uns an, was in dem obigen Codeblock neu ist:

1. Wir haben die Attribute privat gemacht, indem wir das Schlüsselwort private hinzugefügt haben. Das bedeutet, dass auf sie nur innerhalb der MenuItem-Klasse zugegriffen werden kann. Die Verkapselung beginnt mit diesem entscheidenden Schritt.

2. Wir haben eine neue Konstante hinzugefügt: MAX_PRICE:

  • privat (nur innerhalb der Klasse zugänglich)
  • statisch (gemeinsam für alle Instanzen)
  • final (kann nach der Initialisierung nicht geändert werden)
  • auf $100,0 als angemessenen Höchstpreis setzen

3. Wir haben eine setPrice() Methode hinzugefügt, die:

  • Nimmt einen Preisparameter an
  • Bestätigt, dass der Preis nicht negativ ist
  • Prüft, ob der Preis MAX_PRICE nicht übersteigt
  • Wirft IllegalArgumentException mit beschreibenden Meldungen, wenn die Validierung fehlschlägt
  • Legt den Preis nur fest, wenn alle Validierungen erfolgreich sind

4. Wir haben den Konstruktor so geändert, dass er setPrice() verwendet, anstatt den Preis direkt zuzuweisen. Dadurch wird sichergestellt, dass die Preisvalidierung während der Objekterstellung erfolgt.

Wir haben gerade einen der Grundpfeiler eines guten objektorientierten Designs implementiert - dieKapselung. Dieses Paradigma erzwingt Data Hiding und einen kontrollierten Zugriff auf Objektattribute und stellt sicher, dass interne Implementierungsdetails vor externen Eingriffen geschützt sind und nur über wohldefinierte Schnittstellen geändert werden können.

Um das zu verdeutlichen, wenden wir die Kapselung auf das Attributname an. Stell dir vor, wir haben einen Coffee Shop, der nur Lattes, Cappuccinos, Espressos, Americanos und Mokkas serviert.

Unsere Menüpunktnamen können also nur einer der Punkte in dieser Liste sein. Hier ist, wie wir das im Code durchsetzen können:

// Rest of the class here
...
private static final String[] VALID_NAMES = {"latte", "cappuccino", "espresso", "americano", "mocha"};
private String name;
public void setName(String name) {
   String lowercaseName = name.toLowerCase();
   for (String validName : VALID_NAMES) {
       if (validName.equals(lowercaseName)) {
           this.name = name;
           return;
       }
   }
   throw new IllegalArgumentException("Invalid drink name. Must be one of: " + String.join(", ", VALID_NAMES));
}

Der obige Code implementiert die Namensvalidierung für Menüpunkte in einem Coffee Shop. Lass uns das mal aufschlüsseln:

1. Zuerst wird ein privates, statisches, finales Array VALID_NAMES definiert, das die einzigen erlaubten Getränkenamen enthält: Latte, Cappuccino, Espresso, Americano und Mokka. Diese Anordnung ist:

  • privat: nur innerhalb der Klasse zugänglich
  • statisch: gemeinsam für alle Instanzen
  • final: kann nach der Initialisierung nicht geändert werden

2. Er deklariert ein privates String-Feld, um den Namen des Getränks zu speichern

3. Die Methode setName() implementiert die Validierungslogik:

  • Nimmt einen String-Namen als Parameter
  • Konvertiert es in Kleinbuchstaben, um den Vergleich unabhängig von Groß- und Kleinschreibung zu machen
  • Schleifen durch das Array VALID_NAMES
  • Wenn eine Übereinstimmung gefunden wird, setzt sie den Namen und gibt
  • Wenn keine Übereinstimmung gefunden wird, wird eine IllegalArgumentException mit einer beschreibenden Meldung geworfen, die alle gültigen Optionen auflistet

Hier ist die ganze Klasse bis jetzt:

public class MenuItem {
   private String name;
   private double price;

   private static final String[] VALID_NAMES = {"latte", "cappuccino", "espresso", "americano", "mocha"};

   private static final double MAX_PRICE = 100.0;

   public MenuItem(String name, double price) {
       setName(name);
       setPrice(price);
   }

   public void setName(String name) {
       String lowercaseName = name.toLowerCase();
       for (String validName : VALID_NAMES) {
           if (validName.equals(lowercaseName)) {
               this.name = name;
               return;
           }
       }
       throw new IllegalArgumentException("Invalid drink name. Must be one of: " + String.join(", ", VALID_NAMES));
   }

   public void setPrice(double price) {
       if (price < 0) {
           throw new IllegalArgumentException("Price cannot be negative");
       }
       if (price > MAX_PRICE) {
           throw new IllegalArgumentException("Price cannot exceed $" + MAX_PRICE);
       }
       this.price = price;
   }
}

Nachdem wir die Art und Weise, wie Attribute erstellt werden, geschützt haben, wollen wir auch den Zugriff auf sie schützen. Dies geschieht mit Hilfe von Getter-Methoden:

public class MenuItem {
   // Rest of the code here
   ...
   public String getName() {
       return name;
   }
   public double getPrice() {
       return price;
   }
}

Getter-Methoden bieten kontrollierten Zugriff auf private Attribute einer Klasse. Sie lösen das Problem des direkten Attributzugriffs, der zu unerwünschten Änderungen führen und die Kapselung aufbrechen kann.

Ohne Getter könnten wir zum Beispiel direkt auf Attribute zugreifen:

MenuItem item = new MenuItem("Latte", 4.99);
String name = item.name; // Direct access to attribute
item.name = "INVALID"; // Can modify directly, bypassing validation

Mit Gettern erzwingen wir den richtigen Zugriff:

MenuItem item = new MenuItem("Latte", 4.99);
String name = item.getName(); // Controlled access through getter
// item.name = "INVALID"; // Not allowed - must use setName() which validates

Diese Einkapselung:

  1. Schützt die Datenintegrität, indem es ungültige Änderungen verhindert
  2. Ermöglicht es uns, die interne Implementierung zu ändern, ohne den Code zu beeinflussen, der die Klasse verwendet
  3. Bietet einen einzigen Zugangspunkt, der bei Bedarf zusätzliche Logik enthalten kann
  4. Macht den Code wartbarer und weniger anfällig für Fehler

Vererbung

Unsere Klasse fängt an, gut auszusehen, aber es gibt ziemlich viele Probleme mit ihr. Für ein großes Restaurant, das viele verschiedene Gerichte und Getränke anbietet, ist die Klasse zum Beispiel nicht flexibel genug.

Wenn wir verschiedene Arten von Lebensmitteln hinzufügen wollen, stoßen wir auf mehrere Herausforderungen. Einige Gerichte können zum Mitnehmen zubereitet werden, während andere sofort verzehrt werden müssen. Die Menüpunkte können unterschiedliche Preise und Rabatte haben. Es kann sein, dass die Gerichte eine Temperaturkontrolle oder eine besondere Lagerung benötigen. Die Getränke können heiß oder kalt sein und die Zutaten können individuell angepasst werden. Die Artikel müssen eventuell mit Allergeninformationen und Portionsangaben versehen werden. Das aktuelle System wird diesen unterschiedlichen Anforderungen nicht gerecht.

Die Vererbung bietet eine elegante Lösung für all diese Probleme. Sie ermöglicht es uns, spezielle Versionen von Menüpunkten zu erstellen, indem wir eine Basisklasse MenuItem mit gemeinsamen Attributen definieren und dann Unterklassen erstellen, die diese Grundlagen erben und einzigartige Funktionen hinzufügen. 

Wir könnten z.B. eine Klasse Drink für Getränke mit Temperaturoptionen, eine Klasse Food für Artikel, die sofort verzehrt werden müssen, und eine Klasse Dessert für Artikel mit besonderen Lagerungsanforderungen haben - die alle die Kernfunktionalität von Menüpunkten übernehmen.

Erweitern von Klassen

Lasst uns diese Ideen umsetzen, beginnend mit Drink:

public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       this.name = name;
       this.price = price;
       this.isCold = isCold;
   }
  
   public boolean getIsCold() {
       return isCold;
   }
  
   public void setIsCold(boolean isCold) {
       this.isCold = isCold;
   }
}

Um eine Kindklasse zu definieren, die von einer Elternklasse erbt, verwenden wir das Schlüsselwortextends nach dem Namen der Kindklasse, gefolgt von der Elternklasse. Nach der Klassendefinition definieren wir alle neuen Attribute, die dieses Kind hat, und implementieren seinen Konstruktor.

Beachte aber, dass wir die Initialisierung von name und price zusammen mit isColdwiederholen müssen . Das ist nicht ideal, denn die übergeordnete Klasse kann Hunderte von Attributen haben. Außerdem wird der obige Code einen Fehler auslösen, wenn du ihn kompilierst, weil das nicht der richtige Weg ist, um Attribute der Elternklasse zu initialisieren. Der richtige Weg wäre, das Schlüsselwort super zu verwenden:

public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       super(name, price);
       this.isCold = isCold;
   }
  
   public boolean getIsCold() {
       return isCold;
   }
  
   public void setIsCold(boolean isCold) {
       this.isCold = isCold;
   }
}

Das Schlüsselwortsuper wird verwendet, um den Konstruktor der Elternklasse aufzurufen. In diesem Fall ruft super(name, price) den Konstruktor vonMenuItem auf, um diese Attribute zu initialisieren und vermeidet so doppelten Code. Wir müssen nur das neue Attribut isCold initialisieren, das für die KlasseDrink gilt .

Das Schlüsselwort ist sehr flexibel, denn du kannst es verwenden, um in jedem Teil der Kindklasse auf die Elternklasse zu verweisen. Um zum Beispiel eine übergeordnete Methode aufzurufen, verwendest du super.methodName(), während super.attributeName für Attribute steht.

Überschreiben von Methoden

Nehmen wir nun an, wir wollen unseren Klassen eine neue Methode hinzufügen, um den Gesamtpreis nach Steuern zu berechnen. Da verschiedene Menüpunkte unterschiedliche Steuersätze haben können (z. B. zubereitete Speisen im Vergleich zu verpackten Getränken), können wir mithilfe von Methodenüberschreibungen spezifische Steuerberechnungen in jeder Unterklasse implementieren, während wir in der Oberklasse einen gemeinsamen Methodennamen beibehalten.

So sieht das aus:

public class MenuItem {
   // Rest of the MenuItem class
  
   public double calculateTotalPrice() {
       // Default tax rate of 10%
       return price * 1.10;
   }
}
public class Food extends MenuItem {
   private boolean isVegetarian;
  
   public Food(String name, double price, boolean isVegetarian) {
       super(name, price);
       this.isVegetarian = isVegetarian;
   }
  
   @Override
   public double calculateTotalPrice() {
       // Food has 15% tax
       return super.getPrice() * 1.15;
   }
}
public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       super(name, price);
       this.isCold = isCold;
   }
  
   @Override
   public double calculateTotalPrice() {
       // Drinks have 8% tax
       return super.getPrice() * 1.08;
   }
}

In diesem Beispiel erlaubt das Methoden-Overriding jeder Unterklasse, ihre eigene Implementierung von calculateTotalPrice():

Die Basis MenuItem Klasse definiert eine Standardsteuerberechnung von 10%.

Wenn Food und Drink Klassen erweitern MenuItemerweitern, setzen sie diese Methode außer Kraft, um ihre eigenen Steuersätze zu implementieren:

  • Für Lebensmittel gilt ein höherer Steuersatz von 15 %.
  • Getränke haben einen niedrigeren Steuersatz von 8%

Die Anmerkung@Override wird verwendet, um explizit darauf hinzuweisen, dass diese Methoden die Methode der Elternklasse außer Kraft setzen. Das hilft, Fehler abzufangen, wenn die Signatur der Methode nicht mit der übergeordneten Klasse übereinstimmt.

Jede Unterklasse kann weiterhin auf den Preis der Elternklasse zugreifen, indem sie super.getPrice()zugreifen. Das zeigt, wie überschriebene Methoden die Funktionalität der Elternklasse nutzen und gleichzeitig ihr eigenes Verhalten hinzufügen können.

Kurz gesagt ist die Methodenüberschreibung ein integraler Bestandteil der Vererbung, der es Unterklassen ermöglicht, ihre eigene Implementierung von Methoden bereitzustellen, die in der Elternklasse definiert sind, und so ein spezifischeres Verhalten zu ermöglichen, während die gleiche Methodensignatur beibehalten wird.

Abstrakte Klassen

Unsere MenuItem Klassenhierarchie funktioniert, aber es gibt ein Problem: Sollte jeder in der Lage sein, ein einfaches MenuItem Objekt zu erstellen ? Schließlich ist in unserem Restaurant jeder Menüpunkt entweder ein Essen oder ein Getränk - es gibt keine "allgemeinen Menüpunkte".

Wir können dies verhindern, indem wir MenuItem zu einer abstrakten Klasse machen . Eine abstrakte Klasse bietet nur einen Basisentwurf - sie kann nur als Elternklasse für die Vererbung verwendet und nicht direkt instanziiert werden.

Um zu MenuItem abstrakt zu machen, fügen wir das abstract Schlüsselwort nach dem Zugriffsmodifikator hinzu:

public abstract class MenuItem {
   private String name;
   private double price;
  
   public MenuItem(String name, double price) {
       setName(name);
       setPrice(price);
   }
  
   // Existing getters/setters remain the same
  
   // Make this method abstract - every subclass MUST implement it
   public abstract double calculateTotalPrice();
}

Abstrakte Klassen können auch abstrakte Methoden haben, wie calculateTotalPrice() oben. Diese abstrakten Methoden dienen als Verträge, die Unterklassen dazu zwingen, ihre Implementierungen bereitzustellen. Mit anderen Worten: Jede abstrakte Methode in einer abstrakten Klasse muss von den untergeordneten Klassen implementiert werden.

Schreiben wir also um Food und Drink mit diesen Änderungen im Hinterkopf:

public class Food extends MenuItem {
   private boolean isVegetarian;
  
   public Food(String name, double price, boolean isVegetarian) {
       super(name, price);
       this.isVegetarian = isVegetarian;
   }
  
   @Override
   public double calculateTotalPrice() {
       return getPrice() * 1.15;  // 15% tax
   }
}
public class Drink extends MenuItem {
   private boolean hasCaffeine;
  
   public Drink(String name, double price, boolean hasCaffeine) {
       super(name, price);
       this.hasCaffeine = hasCaffeine;
   }
  
   @Override
   public double calculateTotalPrice() {
       return getPrice() * 1.10;  // 10% tax
   }
}

Anhand dieser Menüsystem-Implementierung haben wir gesehen, wie Abstraktion und Vererbung zusammenarbeiten, um flexiblen, wartbaren Code zu erstellen, der sich leicht an unterschiedliche Geschäftsanforderungen anpassen lässt.

Fazit

Heute haben wir einen Blick darauf geworfen, wozu Java als objektorientierte Programmiersprache fähig ist. Wir haben die Grundlagen von Klassen, Objekten und einigen Grundpfeilern der OOP behandelt: Kapselung, Vererbung und Abstraktion anhand eines Restaurant-Menüsystems.

Um dieses System produktionsreif zu machen, musst du noch so viele Dinge lernen, wie Schnittstellen (Teil der Abstraktion), Polymorphismus und OOP-Entwurfsmuster. Um mehr über diese Konzepte zu erfahren, lesen Sie unsere Einführung in OOP in Java Kurs.

Wenn du deine Java-Kenntnisse testen möchtest, kannst du versuchen, einige der Fragen in unserem unserem Artikel Java-Interview-Fragen.

OOP in Java FAQs

Was sind die Voraussetzungen, um dieses Java OOP-Tutorial zu besuchen?

Du solltest über Grundkenntnisse der Java-Programmierung verfügen, einschließlich Datentypen, Variablen, Kontrollfluss (if/else, Schleifen) und grundlegende Syntax. Unser Kurs Einführung in Java deckt diese Grundlagen ab, falls du eine Auffrischung brauchst.

Warum sollte man ein Restaurant-Menüsystem verwenden, um OOP-Konzepte zu erklären?

Ein Restaurant-Menüsystem ist ein intuitives Beispiel, das die Anwendung der OOP-Prinzipien in der Praxis zeigt. Es zeigt natürlich Vererbung (verschiedene Arten von Menüpunkten), Kapselung (Schutz von Preis- und Namenswerten) und Schnittstellen (Treueprogramme, Temperaturkontrolle). Die meisten Menschen wissen, wie Restaurants funktionieren, sodass die Konzepte leichter zu verstehen sind.

Was ist der Unterschied zwischen abstrakten Klassen und Schnittstellen in Java?

  • Eine Klasse kann nur eine abstrakte Klasse erweitern, aber mehrere Schnittstellen implementieren.
  • Abstrakte Klassen können Felder und Konstruktoren haben, Schnittstellen nicht.
  • Abstrakte Klassen können sowohl abstrakte als auch konkrete Methoden haben; Schnittstellen haben traditionell nur abstrakte Methoden (vor Java 8).
  • Abstrakte Klassen bieten eine Basisimplementierung, während Schnittstellen einen Vertrag definieren.

Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Ich bin ein Data Science Content Creator mit über 2 Jahren Erfahrung und einem der größten Follower auf Medium. Ich schreibe gerne ausführliche Artikel über KI und ML mit einem etwas sarkastischen Stil, denn man muss etwas tun, damit sie nicht so langweilig sind. Ich habe mehr als 130 Artikel verfasst und einen DataCamp-Kurs gemacht, ein weiterer ist in Vorbereitung. Meine Inhalte wurden von über 5 Millionen Augenpaaren gesehen, von denen 20.000 zu Followern auf Medium und LinkedIn wurden. 

Themen

Top Java Kurse

Kurs

Introduction to Java

4 hr
6.8K
Learn Java from the ground up with this beginner-friendly course, mastering essential programming concepts and skills.
Siehe DetailsRight Arrow
Kurs starten
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Lehrer/innen und Schüler/innen erhalten das Premium DataCamp kostenlos für ihre gesamte akademische Laufbahn

Keine Hacks, keine Tricks. Schüler/innen und Lehrer/innen, lest weiter, um zu erfahren, wie ihr die Datenerziehung, die euch zusteht, kostenlos bekommen könnt.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

4 Min.

Der Blog

2022-2023 DataCamp Classrooms Jahresbericht

Zu Beginn des neuen Schuljahres ist DataCamp Classrooms motivierter denn je, das Lernen mit Daten zu demokratisieren. In den letzten 12 Monaten sind über 7.650 neue Klassenzimmer hinzugekommen.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

8 Min.

Der Blog

Die 32 besten AWS-Interview-Fragen und Antworten für 2024

Ein kompletter Leitfaden zur Erkundung der grundlegenden, mittleren und fortgeschrittenen AWS-Interview-Fragen, zusammen mit Fragen, die auf realen Situationen basieren. Es deckt alle Bereiche ab und sorgt so für eine abgerundete Vorbereitungsstrategie.
Zoumana Keita 's photo

Zoumana Keita

30 Min.

Der Blog

Q2 2023 DataCamp Donates Digest

DataCamp Donates hat im zweiten Quartal 2023 über 20.000 Stipendien an unsere gemeinnützigen Partner vergeben. Erfahre, wie fleißige benachteiligte Lernende diese Chancen in lebensverändernde berufliche Erfolge verwandelt haben.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

Der Blog

Top 30 Generative KI Interview Fragen und Antworten für 2024

Dieser Blog bietet eine umfassende Sammlung von Fragen und Antworten zu generativen KI-Interviews, die von grundlegenden Konzepten bis hin zu fortgeschrittenen Themen reichen.
Hesam Sheikh Hassani's photo

Hesam Sheikh Hassani

15 Min.

Der Blog

Die 20 besten Snowflake-Interview-Fragen für alle Niveaus

Bist du gerade auf der Suche nach einem Job, der Snowflake nutzt? Bereite dich mit diesen 20 besten Snowflake-Interview-Fragen vor, damit du den Job bekommst!
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

20 Min.

Mehr anzeigenMehr anzeigen