CodeGym /Java-Blog /Random-DE /OOP-Konzepte in Java
Autor
Alex Vypirailenko
Java Developer at Toshiba Global Commerce Solutions

OOP-Konzepte in Java

Veröffentlicht in der Gruppe Random-DE
Eine der größten Stärken von Java ist die objektorientierte Programmierung (OOP). Aus diesem Grund erfreut sich diese Sprache großer Beliebtheit und eignet sich gut für Projekte jeder Größe. Was ist objektorientierte Programmierung? Es ist keine Magie, aber es kann magisch wirken, wenn man sich wirklich darauf einlässt. Bei OOP geht es darum, wie Sie Ihre Software erstellen. Es handelt sich um ein Konzept bzw. um eine Reihe von Oop-Konzepten in Java, mit denen Sie bestimmte Interaktionen und Beziehungen zwischen Java-Objekten erstellen können, um Software effektiv zu entwickeln und zu verwenden. OOP-Konzepte in Java - 1Das klassische OOP umfasst 3 + 1 Hauptkonzepte. Beginnen wir mit den Klassikern.

Das Objekt

Sowohl Java-Objekte als auch reale Objekte weisen zwei Eigenschaften auf: Zustand und Verhalten.

Zum Beispiel hat ein menschliches Objekt einen Zustand (Name, Geschlecht, schlafend oder nicht …) und ein Verhalten (lernt Java, geht, spricht …). Jedes Java-Objekt speichert seinen Zustand in Feldern und legt sein Verhalten über Methoden offen.

Verkapselung

Bei der Datenkapselung werden interne Daten vor der Außenwelt verborgen und der Zugriff darauf nur über öffentlich zugängliche Methoden ermöglicht. Was bedeutet das? Welche Daten? Vor wem verstecken? Ausblenden bedeutet, den direkten Zugriff auf die Datenelemente (Felder) einer Klasse einzuschränken.

So funktioniert es in Java:

  1. Felder werden privat gemacht
  2. Jedes Feld in einer Klasse erhält zwei spezielle Methoden: einen Getter und einen Setter. Getter-Methoden geben den Wert des Feldes zurück. Mit Setter-Methoden können Sie den Wert des Felds auf indirekte, aber zulässige Weise ändern.

Beispiel für die Kapselung in Java-Code:


public class Student {
private int age;
private String name;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this:  firstStudent.name = "John"; 
}
}

Warum sollten Sie Kapselung verwenden?

Der Hauptgrund besteht darin, die Änderung Ihres Codes zu erleichtern. Stellen Sie sich vor, Sie haben eine Bewerbung für eine Hockeyschule und es gibt eine HockeyStudent- Klasse mit zwei Feldern, in denen der Name und das Alter des Schülers zum Zeitpunkt seiner Einschreibung an der Schule gespeichert sind. Etwas wie das:

public class HockeyStudent {
public String name;
public  int ageOfEnrollment;
}
Das Feld „ageOfEnrollment“ ist öffentlich, es gibt keine Getter oder Setter … Diese Klasse wird von vielen anderen Klassen verwendet und alles war in Ordnung, bis ein Entwickler entschied, dass ein einzelnes int-Feld nicht ausreichte. Einige Eishockeyspieler in einer Kohorte sind fast ein Jahr älter als ihre Altersgenossen, daher wäre es praktischer, sie je nach Geburtsmonat in zwei Gruppen aufzuteilen. Daher sollte das Feld „ageOfEnrollment“ in ein int-Array (int[][]) geändert werden : Die erste Zahl steht für ganze Jahre und die zweite für Monate. Jetzt müssen Sie den gesamten Code umgestalten, der die Student- Klasse verwendet! Aber wenn Ihr ageOfEnrollmentWenn das Feld privat ist und Sie Getter und Setter haben, ist alles einfacher. Wenn sich die Anforderung zum Festlegen des Alters eines Schülers ändert, aktualisieren Sie einfach die Logik in der Setter-Methode setAgeOfEnrollment() und Ihre Klassen können Student ohne Probleme weiter verwenden ! Dieses Beispiel ist etwas konstruiert, aber ich hoffe, es erklärt, warum die Verwendung der Kapselung eine großartige Idee ist.

Nachlass

Dieses Prinzip ist auch ohne praktische Erfahrung leichter zu verstehen. Wiederholen Sie sich nicht (DRY) könnte das Motto für das Vererbungskonzept sein. Mit der Vererbung können Sie eine untergeordnete Klasse erstellen, die die Felder und Methoden der übergeordneten Klasse erbt, ohne sie neu zu definieren. Natürlich können Sie die Felder und Methoden der übergeordneten Klasse in der untergeordneten Klasse überschreiben, dies ist jedoch nicht erforderlich. Darüber hinaus können Sie der untergeordneten Klasse neue Zustände und Verhaltensweisen hinzufügen. Übergeordnete Klassen werden manchmal als Superklassen oder Basisklassen bezeichnet, und untergeordnete Klassen werden als Unterklassen bezeichnet. Das Schlüsselwort „extens“ von Java wird verwendet, um das Prinzip der Vererbung im Code zu implementieren.

So funktioniert es in Java:

  1. Erstellen Sie die übergeordnete Klasse.
  2. Erstellen Sie die untergeordnete Klasse mit dem Schlüsselwort „extends“ .
  3. Verwenden Sie im Konstruktor der Child-Klasse die Methode super(parentField1, parentField2, ...) , um die Felder der übergeordneten Klasse festzulegen.

Ein Konstruktor ist eine spezielle Methode, die zum Initialisieren eines neu erstellten Objekts verwendet wird. Ein Konstruktor hat denselben Namen wie sein Klassenname. Es gibt zwei Arten von Konstruktoren: Standardkonstruktoren (Konstruktoren ohne Argumente) und parametrisierte Konstruktoren. Eine Klasse muss mindestens einen Konstruktor haben (sie hat den Standardkonstruktor, wenn keine anderen Konstruktoren definiert wurden) und sie kann viele davon haben.

Jedes Mal, wenn Sie ein neues Objekt erstellen, rufen Sie dessen Konstruktor auf. Im obigen Beispiel tun Sie dies in dieser Zeile:


Student firstStudent = new Student();

Sie verwenden das Schlüsselwort new , um den Standardkonstruktor der Student- Klasse aufzurufen : tudent() .

Einige Regeln:

  1. Eine Klasse kann nur ein übergeordnetes Element haben.
  2. Eine übergeordnete Klasse kann viele untergeordnete Klassen haben.
  3. Eine untergeordnete Klasse kann ihre eigenen untergeordneten Klassen haben.

Beispiel für Vererbung in Java-Code

Lassen Sie uns eine Telefonklasse erstellen.

public class Phone {
    int price;
    double weight;

// Constructor
public Phone(int price, double weight) {
        this.price = price;
        this.weight = weight;
    }

    void orderPhone(){
        System.out.println("Ordering phone...");
    }
}
Natürlich gibt es verschiedene Arten von Telefonen. Erstellen wir also zwei untergeordnete Klassen: eine für Android-Telefone und eine zweite für iPhones. Dann fügen wir einige Felder und Methoden hinzu, die das übergeordnete Element nicht hat. Und wir verwenden super() , um Konstruktoren aufzurufen, um die Felder zu initialisieren, über die die übergeordnete Klasse verfügt.

Beispiel für Vererbung in Java


public class Android extends Phone {

// Some new fields     
String androidVersion;
int screenSize;

    String secretDeviceCode;

// Constructor 
    public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
        super(price, weight); // Android inherits Phone’s fields

        //this - reference to the current object
        //super - reference to the parent object

        this.androidVersion = androidVersion;
        this.screenSize = screenSize;
        this.secretDeviceCode = secretDeviceCode;
    }

	// New Android-specific method, does not exist in the Phone class 
    void installNewAndroidVersion() {
        System.out.println("installNewAndroidVersion invoked...");

    }

}

public class IPhone extends Phone {
   
    boolean fingerPrint;

    public IPhone(int price, double weight, boolean fingerPrint) {
        super(price, weight);
        System.out.println("IPhone constructor was invoked...");
        this.fingerPrint = fingerPrint;
    }

    void deleteIPhoneFromDb() {
        System.out.println("deleteIPhoneFromDb invoked...");
    }

@Override // This is about polymorphism, see below
void orderPhone(){
        System.out.println("Ordering my new iPhone and deleting the old one...");
    }
}
Um es noch einmal zu wiederholen: In Java können Sie durch Vererbung eine Klasse um untergeordnete Klassen erweitern, die die Felder und Methoden der übergeordneten Klasse erben. Dies ist eine hervorragende Möglichkeit, die Wiederverwendbarkeit von Code zu erreichen.

Polymorphismus

Unter Polymorphismus versteht man die Fähigkeit eines Objekts, sich zu verändern, verschiedene Formen anzunehmen bzw. sich auf unterschiedliche Weise zu verhalten. In Java tritt Polymorphismus normalerweise auf, wenn eine übergeordnete Klassenreferenz verwendet wird, um auf ein untergeordnetes Klassenobjekt zu verweisen.

Was das bedeutet und wie es in Java funktioniert:

Was ist Polymorphismus in Java? Im Allgemeinen bedeutet das, dass Sie denselben Methodennamen für verschiedene Zwecke verwenden können. In Java gibt es zwei Arten von Polymorphismus: Methodenüberschreibung (dynamischer Polymorphismus) und Methodenüberladung (statischer Polymorphismus).

Überschreibende Methode

Sie können die Methode einer übergeordneten Klasse in einer untergeordneten Klasse überschreiben und so eine andere Funktionsweise erzwingen. Erstellen wir eine übergeordnete Klasse „Musician“ mit einer play() -Methode.

Beispiel für Polymorphismus in Java-Code


   public class Musician {
    String name;
    int age;

    // Default constructor
    public Musician() {
    }

    // Parameterized constructor
    public Musician(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void play() {
        System.out.println("I am playing my instrument...");
    }
}
Verschiedene Musiker verwenden unterschiedliche Instrumente. Erstellen wir zwei untergeordnete Klassen: Pianist und Violinist . Dank Polymorphismus führt jeder seine eigene Version der play()- Methode aus. Beim Überschreiben können Sie die Annotation @Override verwenden , dies ist jedoch nicht erforderlich.

public class Pianist extends Musician {
    
    String favoritePianoType;

    public Pianist(String name, int age, String favoritePianoType) {
        super(name, age);
        this.favoritePianoType = favoritePianoType;
    }


    @Override
void play(){
        System.out.println("I am playing the piano...");
    }
}
Der Geigenspieler kann ein Solist oder Mitglied eines Orchesters sein. Berücksichtigen wir dies, wenn wir unsere play()- Methode überschreiben.

public class Violinist extends Musician { 
    boolean isSoloist; 

public Violinist(String name, int age, boolean isSoloist) {
            super(name, age);
            this.isSoloist = isSoloist;
        }


    @Override
void play(){
if (isSoloist) 
        System.out.println("I am playing the violin solo...");
else 
System.out.println("I am playing the violin in an orchestra...");

    }
}
Lassen Sie uns eine Demo- Klasse erstellen, in der wir drei Objekte erstellen, eine Instanz jeder der zuvor erstellten Klassen. Wir werden sehen, welche Ergebnisse wir erzielen.

public class Demo {
  public static void main(String[] args) {
  Musician musician = new Musician();
  Violinist violinist = new Violinist("John", 32, true);
  Pianist pianist = new Pianist("Glen", 30, "Acoustic"); 

  System.out.println("Musician said:");
  musician.play();
  System.out.println("Violinist said:");
  violinist.play();
  System.out.println("Pianist said:");
  pianist.play();
    }
}
Das bekommen wir:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
Jeder Geiger und Pianist ist ein Musiker, aber nicht jeder Musiker ist ein Bratschist oder Pianist. Das bedeutet, dass Sie die Spielmethode des Musikers verwenden können, wenn Sie keine neue erstellen müssen. Oder Sie können die Methode des Elternteils vom Kind aus aufrufen, indem Sie das Schlüsselwort super verwenden . Machen wir das im Pianist-Code:

public class Pianist extends Musician {

    String favoritePianoType;
    
    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
}
Rufen wir nun unsere main() -Methode in der Demo- Klasse auf. Hier ist das Ergebnis:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...

Methodenüberladung

Unter Methodenüberladung versteht man die Verwendung verschiedener Methoden mit demselben Namen in derselben Klasse. Sie müssen sich hinsichtlich der Anzahl, Reihenfolge oder Art ihrer Parameter unterscheiden. Angenommen, ein Pianist kann ein akustisches und ein elektrisches Klavier spielen. Um ein elektrisches Instrument zu spielen, benötigt der Musiker Strom. Lassen Sie uns zwei verschiedene play()- Methoden erstellen. Das erste ohne Parameter, für ein akustisches Klavier, und das zweite mit einem Parameter, der angibt, ob Strom verfügbar ist.

public class Pianist extends Musician {

    String name;
    int age;
    String favoritePianoType;

    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
    void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            System.out.println("I am playing the piano...");
        }
        else System.out.println("I can't play this without electricity.");
    }
}
Übrigens können Sie die erste play()- Methode innerhalb der zweiten play(boolean) -Methode auf folgende Weise verwenden:

void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            play();
        }
        else System.out.println("I can't play this without electricity.");
    }
Fügen wir unserer Demo- Klasse einige Zeilen hinzu, um unsere Überladung zu demonstrieren:

public class Demo {
    public static void main(String[] args) {

        Musician musician = new Musician();
        Violinist violinist = new Violinist("John", 23, true);
        Pianist pianist = new Pianist("Glen", 30, "Acoustic"); 

        System.out.println("Musician said:");
        musician.play();
        System.out.println("Violinist said:");
        violinist.play();
        System.out.println("Pianist said:");
        pianist.play();
        System.out.println("The pianist will now try the electric piano:");
        pianist.play(true);
        System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
        pianist.play(false);
    }
}
Hier ist das Ergebnis:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
Java weiß anhand seiner Parameter und des Objekttyps, welche Methode verwendet werden soll. Das ist Polymorphismus.

Abstraktion

Wenn wir eine Klasse definieren, versuchen wir, ein Modell von etwas zu erstellen. Angenommen, wir schreiben ein Videospiel namens MyRacer mit verschiedenen Rennwagen. Ein Spieler kann eines davon auswählen und es später aktualisieren oder ein anderes kaufen. Also... Was ist ein Auto? Ein Auto ist eine ziemlich komplizierte Sache, aber wenn wir versuchen, ein Rennvideospiel zu erstellen (im Gegensatz zu einem Fahrsimulator), müssen wir nicht die tausenden darin enthaltenen Zahnräder und Dichtungen beschreiben. Wir brauchen das Modell, die Höchstgeschwindigkeit, die Manövriereigenschaften, den Preis, die Farbe … Und vielleicht reicht das. Das ist das Modell eines Autos für unser Spiel. Angenommen, wir beschließen später in MyRacer 2, Reifen hinzuzufügen, die das Fahrverhalten auf der Straße beeinflussen. Hier ist das Modell anders, da wir mehr Details hinzugefügt haben. Lassen' s definieren Datenabstraktion als den Prozess, bei dem nur die wichtigen (oder notwendigen) Merkmale eines Objekts identifiziert und alle irrelevanten Details ignoriert werden. Es gibt verschiedene Abstraktionsebenen. Wenn Sie beispielsweise Fahrgast in einem Bus sind, müssen Sie wissen, wie Ihr Bus aussieht und wohin er fährt, aber Sie müssen nicht wissen, wie man ihn fährt. Wenn Sie Busfahrer sind, müssen Sie nicht wissen, wie man einen neuen Bus baut – Sie müssen nur wissen, wie man ihn fährt. Wenn Sie jedoch ein Bushersteller sind, müssen Sie auf eine niedrigere Abstraktionsebene gehen, da Ihnen die Details des Busdesigns sehr wichtig sind. Ich hoffe du verstehst was ich meine.

So funktioniert es in Java:

Lassen Sie uns vier Abstraktionsebenen in Java, oder besser gesagt in OOP, erstellen – von der niedrigsten (spezifischsten) bis zur höchsten (abstraktesten).
  1. Die niedrigste Abstraktionsebene ist ein bestimmtes Objekt. Es handelt sich um eine Entität mit einer Reihe von Merkmalen, die zu einer bestimmten Klasse gehören. Es verfügt über bestimmte Feldwerte

  2. Eine Vorlage zum Erstellen von Objekten ist eine Klasse. Es handelt sich um eine Beschreibung einer Reihe von Objekten mit ähnlichen Eigenschaften und interner Struktur.

  3. Eine abstrakte Klasse ist eine abstrakte Beschreibung der Merkmale einer Reihe von Klassen (sie dient als Vorlage für die Vererbung durch andere Klassen). Da es einen hohen Abstraktionsgrad aufweist, ist es unmöglich, Objekte direkt aus einer abstrakten Klasse zu erstellen. Zum Erstellen von Objekten können nur untergeordnete Klassen abstrakter Klassen verwendet werden. Eine abstrakte Klasse kann Methoden mit einer Implementierung enthalten, dies ist jedoch keine Voraussetzung.

  4. Eine Schnittstelle ist ein Konstrukt der Java-Programmiersprache, das nur abstrakte öffentliche Methoden und statische Konstantenfelder (final static) enthält. Mit anderen Worten: Es können weder abstrakte Klassen noch Schnittstellen zum Generieren von Objekten verwendet werden.

Übrigens können Schnittstellen in Java 8 oder höher nicht nur abstrakte Methoden und Konstanten, sondern auch Standard- und statische Methoden haben. In Java definiert eine Schnittstelle ein Verhalten, während eine abstrakte Klasse zum Erstellen einer Hierarchie verwendet wird. Eine Schnittstelle kann durch mehrere Klassen implementiert werden.

Beispiel einer Schnittstelle im Java-Code


interface Human {
	public void struggle();
	public void protect();
}

interface Vulcan {
	int angleOfPointyEars; 
	public void turnOffEmotions(boolean isOn);
	public void telepathy();
}
Sie können mehr als eine Schnittstelle implementieren

The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
	public void protect() {
System.out.println("You are under my protection!”);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
	public void telepathy() {
System.out.println("Connecting to your brain...");
}

}
Für Studienanfänger werden hier alle Hauptkonzepte der objektorientierten Programmierung in Java behandelt. Neben den vier Haupt-OOP-Prinzipien verfügt Java auch über Assoziation, Aggregation und Zusammensetzung. Man kann sie „zusätzliche OOP-Prinzipien“ nennen. Sie verdienen einen eigenen Artikel.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION