Inhalt
Ausnahmen, Statische Variablen und Methoden, Vererbung und Polymorphismus, Akstrakte Klassen
Ausnahmenbehandlung (Exceptions)
In Java gibt es zwei Arten von Ausnahmen: “checked exceptions” und “unchecked exceptions”.
Checked exceptions
“Checked exceptions” sind Ausnahmen, die explizit in der Methode deklariert werden müssen, in der sie ausgelöst werden können. Das bedeutet, dass jeder Code, der eine Methode aufruft, die eine “checked exception” werfen kann, auch bereit sein muss, diese Ausnahme abzufangen. Beispiele für “checked exceptions” sind FileNotFoundException, SQLException, etc.
Unchecked exceptions
“Unchecked exceptions” hingegen sind Ausnahmen, die nicht explizit deklariert werden müssen. Sie werden beispielsweise durch Programmierfehler wie NullPointerException, IndexOutOfBoundsException oder ArithmeticException verursacht. Diese Ausnahmen müssen nicht abgefangen werden und es ist auch optional, ob man sie in der Methode deklariert, in der sie ausgelöst werden können.
Hier ist ein Beispiel, das den Unterschied zwischen “checked exceptions” und “unchecked exceptions” veranschaulicht:
Beispiel
import java.io.*;
class Main {
public static void main(String[] args) {
// Checked exception example
try {
FileInputStream fis = new FileInputStream("file.txt");
} catch (FileNotFoundException e) {
System.out.println("File not found.");
}
// Unchecked exception example
int[] numbers = {1, 2, 3};
try {
int x = numbers[5];
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index out of bounds.");
}
}
}
In diesem Beispiel wird eine “checked exception” abgefangen, wenn das Programm versucht, eine Datei zu öffnen, die nicht vorhanden ist. Eine “unchecked exception” wird abgefangen, wenn das Programm versucht, auf einen ungültigen Index im Array numbers
zuzugreifen.
Statische Variablen und Methoden
Statische Variablen und Methoden in Java sind solche, die direkt auf die Klasse und nicht auf eine bestimmte Instanz der Klasse zugreifen.
Definition statischer Variablen
Statische Variablen, auch als Klassenvariablen bezeichnet, werden mit dem Schlüsselwort static
vor der Deklaration der Variablen definiert und sind nur einmal für die gesamte Klasse vorhanden. Sie werden geteilt von allen Instanzen der Klasse und über die Instanzen hinaus existieren sie, auch wenn keine Instanz existiert.
public class MyClass {
public static int staticVariable;
}
Definition statischer Methoden
Statische Methoden, auch als Klassenmethoden bezeichnet, werden mit dem Schlüsselwort static
vor der Signatur der Methode definiert. Sie haben keinen Zugriff auf die Instanzvariablen der Klasse und können daher nur auf statischen Variablen und Parametern operieren.
public class MyClass {
public static void staticMethod() {
// method body
}
}
Zugriff auf statische Variablen und Aufruf von statischen Methoden
In beiden Beispielen, kann die Variable staticVariable
und die Methode staticMethod
direkt über den Klassennamen aufgerufen werden, ohne dass eine Instanz der Klasse erstellt werden muss:
MyClass.staticVariable = 5;
MyClass.staticMethod();
Anwendung anhand einer Klasse Math
Ein Beispiel, wie man statische Variablen und Methoden verwenden kann, ist eine Klasse Math
die Methoden und Variablen enthält, die Mathematische Operationen durchführen. Zum Beispiel kann es eine statische Methode pow
geben, die eine potenzierende Funktion darstellt und die nicht auf eine Instanz der Klasse Math
zugreifen muss.
public class Math {
public static double PI = 3.14;
public static double pow(double base, double exponent) {
return Math.pow(base, exponent);
}
}
Es kann dann so verwendet werden:
double result = Math.pow ( 10, 4 );
Statische Variablen und Methoden werden oft verwendet, um Daten und Funktionalität bereitzustellen, die allen Instanzen einer Klasse gemeinsam sind, und die nicht von einer bestimmten Instanz abhängen. Sie sind auch nützlich, um Ressourcen und Informationen zu verwalten, die für die gesamte Klasse gelten.
Vererbung und Polymorphismus
In Java ist Vererbung ein Konzept, bei dem eine Klasse (die Unterklasse) von einer anderen Klasse (die Oberklasse) erbt. Die Unterklasse erbt alle Attribute und Methoden der Oberklasse und kann diese überschreiben oder erweitern, um an ihre eigenen Bedürfnisse anzupassen.
Das Schlüsselwort, das in Java verwendet wird, um Vererbung darzustellen, ist extends
. Hier ist ein Beispiel:
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void makeSound() {
System.out.println("The animal makes a sound.");
}
public String getName() {
return name;
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("The dog barks.");
}
}
In diesem Beispiel erbt die Klasse Dog von der Klasse Animal und überschreibt die Methode makeSound()
. Daher wird bei einem Aufruf der Methode makeSound()
auf einem Dog-Objekt die Meldung “The dog barks.” anstelle von “The animal makes a sound.” ausgegeben.
Mehrere Ebenen bei der Vererbung
Es ist auch möglich, mehrere Ebenen von Vererbung zu haben, indem man von einer Unterklasse einer anderen Klasse erbt. Hier ist ein Beispiel:
class Mammal extends Animal {
private boolean hasFur;
public Mammal(String name, boolean hasFur) {
super(name);
this.hasFur = hasFur;
}
public boolean getHasFur() {
return hasFur;
}
}
class Cat extends Mammal {
public Cat(String name, boolean hasFur) {
super(name, hasFur);
}
@Override
public void makeSound() {
System.out.println("The cat meows.");
}
}
In diesem Beispiel erbt die Klasse Cat
von der Klasse Mammal
, die wiederum von der Klasse Animal
erbt. Daher hat die Klasse Cat
Zugriff auf alle Attribute und Methoden sowohl der Klasse Mammal
als auch der Klasse Animal
.
Vererbung und Überladen von Methoden
Methoden in Unterklassen können überladen werden, indem man eine Methode mit dem gleichen Namen in der Unterklasse definiert und eine andere Signatur verwendet. Dies bedeutet, dass die Methode in der Unterklasse eine andere Anzahl oder Typen von Argumenten hat als die gleichnamige Methode in der Oberklasse.
Hier ist ein Beispiel:
class Animal {
public void makeSound() {
System.out.println("The animal makes a sound.");
}
}
class Dog extends Animal {
public void makeSound(String barkSound) {
System.out.println("The dog makes a " + barkSound + " sound.");
}
}
In diesem Beispiel definiert die Klasse Dog
eine Methode makeSound
, die die gleiche Signatur hat wie die Methode in der Klasse Animal
. Da die Methoden jedoch unterschiedliche Signaturen haben, überlädt die Klasse Dog
die Methode makeSound
und nicht, dass sie sie überschreibt.
Wenn eine Unterklasse eine Methode überlädt, kann sie auf die gleichnamige Methode der Oberklasse mit dem Schlüsselwort super
verweisen. Hierdurch kann die Funktionalität der Methode in der Oberklasse kombiniert werden mit der Funktionalität der überladenen Methode in der Unterklasse.
Wenn eine Unterklasse eine Methode mit der gleichen Signatur wie eine Methode in der Oberklasse definiert, wird die Methode in der Oberklasse überschrieben und nicht überladen.
Das Schlüsselwort super
Das Schlüsselwort super in Java wird verwendet, um auf die Methoden oder Felder einer Oberklasse zu verweisen. Es ist besonders nützlich, wenn es in einer Unterklasse verwendet wird, um auf die gleichnamigen Methoden oder Felder der Oberklasse zu verweisen.
Hier ist ein Beispiel:
class Animal {
public void makeSound() {
System.out.println("The animal makes a sound.");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
super.makeSound();
System.out.println("The dog barks.");
}
}
In diesem Beispiel überschreibt die Klasse Dog die Methode makeSound
der Klasse Animal
. Die Methode makeSound
in der Klasse Dog ruft jedoch zuerst die gleichnamige Methode der Oberklasse auf, indem sie das Schlüsselwort super
verwendet. Hierdurch kann die Ausgabe der Methode in der Oberklasse kombiniert werden mit der Ausgabe der Methode in der Unterklasse.
Das Schlüsselwort super
kann auch verwendet werden, um Konstruktoren einer Oberklasse aufzurufen.
Konstruktoren werden nicht vererbt
n Java werden Konstruktoren nicht automatisch geerbt. Wenn eine Unterklasse eine Oberklasse erbt, muss sie explizit den Konstruktor der Oberklasse aufrufen, um sicherzustellen, dass die entsprechenden Initialisierungen durchgeführt werden.
Dies kann mit dem Schlüsselwort super
erfolgen, das auf den Konstruktor der Oberklasse verweist. Hier ist ein Beispiel:
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void makeSound() {
System.out.println("The animal makes a sound.");
}
public String getName() {
return name;
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("The dog barks.");
}
}
In diesem Beispiel ruft die Klasse Dog
den Konstruktor der Klasse Animal
auf, indem sie das Schlüsselwort super
verwendet. Hierdurch wird sichergestellt, dass das Attribut name
für das Dog
-Objekt initialisiert wird.
Wenn eine Unterklasse keinen expliziten Konstruktor hat, wird automatisch ein Konstruktor ohne Argumente bereitgestellt. Wenn jedoch ein Konstruktor mit Argumenten hinzugefügt wird, muss ein expliziter Aufruf des Konstruktors der Oberklasse hinzugefügt werden, da ansonsten ein Kompilierungsfehler auftritt.
Polymorphismus
Abstrakte Klassen
Abstrakte Klassen sind Klassen in Java, die nicht vollständig implementiert werden und daher nicht direkt instanziiert werden können. Stattdessen dienen sie als Vorlage für andere Klassen, die von ihnen erben und ihre Methoden implementieren.
Abstrakte Klassen haben die Möglichkeit, sowohl abstrakte Methoden als auch konkrete Methoden zu enthalten. Abstrakte Methoden sind Methoden, die in der abstrakten Klasse deklariert werden, aber keine Implementation haben. Sie müssen von jeder Klasse implementiert werden, die von der abstrakten Klasse erbt. Konkrete Methoden hingegen sind Methoden, die in der abstrakten Klasse implementiert werden und von Subklassen verwendet werden können, ohne dass sie diese erneut implementieren müssen.
Eine abstrakte Klasse wird in Java mit dem Schlüsselwort abstract
deklariert. Hier ist ein Beispiel für eine abstrakte Klasse in Java:
public abstract class Shape {
// Abstrakte Methode
public abstract double getArea();
// Konkrete Methode
public double getPerimeter() {
// Implementation hier
}
}
Um von einer abstrakten Klasse zu erben, verwendet man das Schlüsselwort extends
und implementiert alle abstrakten Methoden der abstrakten Klasse. Hier ist ein Beispiel für eine Subklasse, die von der obigen abstrakten Klasse Shape
erbt:
public class Rectangle extends Shape {
private double width;
private double height;
// Konstruktor und andere Methoden hier
// Implementierung der abstrakten Methode "getArea"
@Override
public double getArea() {
return width * height;
}
}
Abstrakte Klassen sind in Java besonders nützlich, wenn man eine Vorlage für eine Gruppe von Klassen schaffen möchte, die gemeinsame Methoden und Eigenschaften haben, aber unterschiedliche Implementationen für bestimmte Methoden haben. Sie können auch verwendet werden, um eine Hierarchie von Klassen zu bauen, bei der bestimmte Methoden erst in tieferen Ebenen der Hierarchie definiert werden.
- Ausnahmen, Statische Variablen und Methoden, Vererbung und Polymorphismus, Akstrakte Klassen