Objektorientierte Programmierung: Unterschied zwischen den Versionen

Aus CCWiki
Zur Navigation springen Zur Suche springen
 
(117 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
= Objektorientierte Programmierung =
<cite>Die objektorientierte Programmierung (kurz OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft. Ein Modell dieser Strukturen wird in der Entwurfsphase aufgestellt. Es enthält Informationen über die auftretenden Objekte und deren Abstraktionen, ihre Typen. Die Umsetzung dieser Denkweise erfordert die Einführung verschiedener Konzepte, insbesondere {{AL|Klasse|Klassen}}, {{AL|Vererbung}}, [[{{PAGENAMEE}}#Polymorphismus|Polymorphie]] und [[{{PAGENAMEE}}#Has_A|spätes Binden (dynamisches Binden)]].</cite><ref>https://de.wikipedia.org/wiki/{{PAGENAMEE}}</ref>
<cite>Die objektorientierte Programmierung (kurz OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft. Ein Modell dieser Strukturen wird in der Entwurfsphase aufgestellt. Es enthält Informationen über die auftretenden Objekte und deren Abstraktionen, ihre Typen. Die Umsetzung dieser Denkweise erfordert die Einführung verschiedener Konzepte, insbesondere [[{{PAGENAMEE}}#Klasse|Klassen]], [[{{PAGENAMEE}}#Vererbung|Vererbung]], [[{{PAGENAMEE}}#Polymorphismus|Polymorphie]] und [[{{PAGENAMEE}}#Has_A|spätes Binden (dynamisches Binden)]].</cite><ref>https://de.wikipedia.org/wiki/{{PAGENAMEE}}</ref>
{{TOC limit|4}}
 
= Java =
= Java =
Java ist eine objektorientierte Programmiersprache. In einigen Punkten nimmt Sie die '''Objektorientierung''' nicht so streng wie andere Sprachen. Ein Beispiel hierfür wären die '''primitiven Datentypen'''. Somit ist in Java nicht alles ein '''Objekt'''.<br>
Java ist eine objektorientierte Programmiersprache. In einigen Punkten nimmt Sie die '''Objektorientierung''' nicht so streng wie andere Sprachen. Ein Beispiel hierfür wären die {{Link|Primitive_Datentypen|primitiven Datentypen}}. Somit ist in Java nicht alles ein '''Objekt''' {{Link|Objekt.2FInstanz_VS._Klasse|(Was ist ein Objekt?)}} .<br>
== Primitive Datentypen ==
== Primitive Datentypen ==
In Java gibt es eine vielzahl von '''primitiven Datentypen'''. Sie unterscheiden sich darin, dass Sie kein '''Object''' sind. Sie haben keine '''Methoden''' und auch keine '''Attribute'''. Wird eine Variable mit einem '''primitiven Datentyp''' erstellt und dieser Variable ein Wert zugewiesen, so enthält diese Variable den wirklichen Wert und nicht nur eine '''Referenz''' auf das eigentliche Objekt:
In Java gibt es eine vielzahl von '''primitiven Datentypen'''. Sie unterscheiden sich darin, dass Sie kein '''Objekt''' sind. Sie haben keine {{AL|Methoden}} und auch keine {{AL|Attribute}}. Wird eine Variable mit einem '''primitiven Datentyp''' erstellt und dieser Variable ein Wert zugewiesen, so enthält diese Variable den wirklichen '''Wert''' und nicht nur eine '''Referenz''' auf das eigentliche '''Objekt''':
<syntaxhighlight lang='java' line>
{{JML|code=//Variable a enthält den Wert 10
//Variable a enthält den Wert 10
int a = 10;
int a = 10;
//Variable b enthält nur den Verweis auf das Integer Objekt mit dem Wert 10
//Variable b enthält nur den Verweis auf das Integer Objekt mit dem Wert 10
Integer b = Integer.valueOf(10);
Integer b = Integer.valueOf(10);
</syntaxhighlight>
}}
Zu jedem primitiven Datentyp, gibt es einen entsprechende Klasse:
Zu jedem primitiven Datentyp gibt es eine entsprechende Klasse:
{| class="wikitable"
{| class="wikitable"
|+ Entsprechende Klasse für primitive Datentypen
|+ Entsprechende Klasse für primitive Datentypen
|-
|-
! primitiver Datentyp !! Klasse
! primitiver Datentyp !! Klasse/Komplexer Datentyp !! Beschreibung
|-
| {{JSL|int}} || {{JSL|java.lang.Integer}} || Ganzzahl in Zweierkomplent Darstellung, max: 2<sup>31</sup>-1, min: -2<sup>31</sup>
|-
|-
| int || Integer
| {{JSL|long}} || {{JSL|java.lang.Long}} || Ganzzahl in Zweierkomplent Darstellung, max: 2<sup>63</sup>-1, min: -2<sup>63</sup>
|-
|-
| float || Float
| {{JSL|float}} || {{JSL|java.lang.Float}} || Fließkommazahl
|-
|-
| double || Double
| {{JSL|double}} || {{JSL|java.lang.Double}} || Fließkommazahl mit doppelter Genauigkeit
|-
|-
| char || Character
| {{JSL|char}} || {{JSL|java.lang.Character}} || Einzelnes Zeichen
|-
|-
| boolean || Boolean
| {{JSL|boolean}} || {{JSL|java.lang.Boolean}} || Wahrheitswert, {{JSL|true}} oder {{JSL|false}}
|}
|}
Primitive Datentypen können automatisch in ihr entsprechendes Klassenäquivalent umgewandelt werden und natürlich umgekehrt. Dieser Prozess nennt sich '''Autoboxing'''. Dies ist vorallem von Vorteil, wenn mit '''Collections (Listen,...)''' gearbeitet wird, da diese nur mit Klassen funktionieren.
Primitive Datentypen können automatisch in ihr entsprechendes Klassenäquivalent (in ein '''Objekt''') umgewandelt werden und natürlich umgekehrt. Dieser Prozess nennt sich '''Autoboxing'''. Dies ist vor allem von Vorteil, wenn mit '''Collections (Listen,...)''' gearbeitet wird, da diese nur mit '''Objekten''' funktionieren.
<syntaxhighlight lang='java' line>
{{JML|code=
//Umwandlung der Zahl 10 in ein Integer Object
//Umwandlung der Zahl 10 in ein Integer Object
Integer b = 10;
Integer b = 10;
//Integer Object wird in primitive Zahl 10 umgewandelt
//Integer Object wird in primitive Zahl 10 umgewandelt
int c = b;
int c = b;
</syntaxhighlight>
}}
 
== Klasse ==
== Klasse ==
<cite>Unter einer Klasse (auch Objekttyp genannt) versteht man in der objektorientierten Programmierung ein abstraktes Modell bzw. einen Bauplan für eine Reihe von ähnlichen Objekten.
<cite>Unter einer Klasse (auch Objekttyp genannt) versteht man in der objektorientierten Programmierung ein abstraktes Modell bzw. einen Bauplan für eine Reihe von ähnlichen Objekten. Die Klasse dient als Bauplan für die Abbildung von realen Objekten in Softwareobjekte und beschreibt Attribute (Eigenschaften) und Methoden (Verhaltensweisen) der Objekte. Verallgemeinernd könnte man auch sagen, dass eine Klasse dem Datentyp eines Objekts entspricht.<ref>https://de.wikipedia.org/wiki/Klasse_(Objektorientierung)</ref></cite><br>
Die Klasse dient als Bauplan für die Abbildung von realen Objekten in Softwareobjekte und beschreibt Attribute (Eigenschaften) und Methoden (Verhaltensweisen) der Objekte. Verallgemeinernd könnte man auch sagen, dass eine Klasse dem Datentyp eines Objekts entspricht.<ref>https://de.wikipedia.org/wiki/Klasse_(Objektorientierung)</ref></cite><br>
Wir sehen, eine '''Klasse''' kann man sich wie eine Vorlage vorstellen, aus dieser dann '''Instanzen''' bzw. '''Objekte''' mittels des Schlüsselworts {{JSL|new}} erstellt werden. Weiters sei erwähnt, dass jede '''Klasse''' egal ob es hingeschrieben wird oder nicht, von der Java '''Klasse''' {{JSL|java.lang.Object}} erbt.
Wir sehen, eine [[{{PAGENAMEE}}#Klasse|Klasse]] kann man sich wie eine Vorlage vorstellen, aus dieser dann '''Instanzen / Objekte''' mittels des Schlüsselworts '''new''' erstellt werden. Weiters sei erwähnt, dass jede [[{{PAGENAMEE}}#Klasse|Klasse]] egal ob es hingeschrieben wird oder nicht, von der [[{{PAGENAMEE}}#Klasse|Klasse]] '''java.lang.Object''' erbt.
=== Konstruktor ===
=== Konstruktor ===
Jede [[{{PAGENAMEE}}#Klasse|Klasse]] hat einen Konstruktor, ist dieser leer, d.h. er nimmt keine Parameter, muss dieser nicht geschrieben werden. Der Konstruktor heißt immer gleich wie die Klasse selbst.
Jede '''Klasse''' hat einen Konstruktor, ist dieser leer, d.h. er nimmt keine Parameter, muss dieser nicht geschrieben werden. Der Konstruktor heißt immer gleich wie die '''Klasse''' selbst.
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   private String name;
   private String name;
Zeile 50: Zeile 50:
//Instanz von Animal erstellen
//Instanz von Animal erstellen
Animal a = new Animal();
Animal a = new Animal();
</syntaxhighlight>
}}
Wollen wir nur beispielsweise garantieren, dass ein '''Animal''' bei der Instanzierung einen Namen hat, so könnten wir den '''Konstruktor''' verändern.
Wollen wir nun beispielsweise garantieren, dass ein '''Animal''' bei der Instanzierung einen Namen hat, so könnten wir den '''Konstruktor''' verändern.
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   private String name;
   private String name;
Zeile 63: Zeile 63:
//Instanz von Animal erstellen
//Instanz von Animal erstellen
Animal a = new Animal("Alfons");
Animal a = new Animal("Alfons");
</syntaxhighlight>
}}
Es können auch mehrere '''Konstruktoren''' existieren. Diese können sich auch gegenseitig aufrufen. Sobald ein '''Konstruktor''' definiert wird, so kann der Standardkonstruktor nicht mehr zur Instanzierung verwendet werden, dieser muss explizit hingeschrieben werden, wenn nötig.
Es können auch mehrere '''Konstruktoren''' existieren. Diese können sich auch gegenseitig aufrufen. Sobald ein '''Konstruktor''' definiert wird, so kann der '''Standardkonstruktor''' nicht mehr zur Instanzierung verwendet werden. Soll der '''Standardkonstruktor''' weiter verfügbar sein, so muss dieser explizit hingeschrieben werden. Haben wir mehrere '''Konstruktoren''' so können wir auch von '''Konstruktor {{Link|Überladen_von_Methoden|Überladung}}''' sprechen.
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   private String name;
   private String name;
Zeile 82: Zeile 82:
//Weitere Instanz mit gewähltem Namen
//Weitere Instanz mit gewähltem Namen
Animal b = new Animal("Alfons"); //Alfons
Animal b = new Animal("Alfons"); //Alfons
 
}}
</syntaxhighlight>


=== Attribute ===
=== Attribute ===
Klassen haben Attribute (Eigenschaften). Wir unterscheiden hier zwei Varianten von Attributen. '''Instanz Attribute''' und '''Klassen Attribute'''.
'''Klassen''' haben '''Attribute''' (Eigenschaften). Hier werden zwei Varianten von '''Attributen''' unterschieden. '''Instanzattribute''' und '''Klassenattribute'''.
==== Instanz Attribute ====
==== Instanzattribut ====
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   public String name;
   public String name;
Zeile 96: Zeile 95:
Animal a = new Animal();
Animal a = new Animal();
System.out.println(a.name);
System.out.println(a.name);
</syntaxhighlight>
}}
Jede Instanz verfügt über eigene Instanzvariablen, diese werden nicht untereinander geteilt.
Jede '''Instanz''' einer '''Klasse''' verfügt über eigene '''Instanzattribute''', diese werden nicht untereinander geteilt. Das heißt, gibt es mehrere '''Instanzen''' der selben '''Klasse''', so haben die '''Instanzattribute''' unterschiedliche Werte.


==== Klassen Attribute ====
==== Klassenattribut ====
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   public static double PI = 3.14;
   public static double PI = 3.14;
Zeile 106: Zeile 105:
//Korrekter Zugriff
//Korrekter Zugriff
System.out.println(Animal.PI);
System.out.println(Animal.PI);
</syntaxhighlight>
}}
Attribute die mit dem Schlüsselwort '''static''' gekennzeichnet werden, existieren nur einmal. Vereinfacht gesagt, diese Attribute sind an die Klasse und nicht an die Instanz gebunden.
'''Attribute''' die mit dem Schlüsselwort '''static''' gekennzeichnet werden, existieren nur einmal. Vereinfacht gesagt, diese '''Attribute''' sind an die '''Klasse''' und nicht an die '''Instanz''' gebunden.


=== Methoden ===  
=== Methoden ===  
'''Methoden''' sind Prozeduren (Abläufe) die in [[{{PAGENAMEE}}#Klasse|Klassen]] Definiert werden. Durch Methoden können '''Objekte''' miteinander interagieren, bzw. deren Zustand kann modifiziert werden. Genauso wie bei den '''Attributen''' können '''Methoden''' für eine '''Instanz''' oder mit dem Schlüsselwort '''static''' für die [[{{PAGENAMEE}}#Klasse|Klasse]] definiert werden.<br><br>
'''Methoden''' sind Abläufe oder Verhaltensweisen die in '''Klassen''' definiert werden. Durch Methoden können '''Objekte''' miteinander interagieren, bzw. deren Zustand kann modifiziert werden. Genauso wie bei den '''Attributen''' können '''Methoden''' für eine '''Instanz''' mit dem Schlüsselwort {{JSL|static}} für die '''Klasse''' definiert werden.<br><br>
'''Methoden''' haben zumindest:
'''Methoden''' haben zumindest:
* Methodennamen
* Methodennamen
* Rückgabetype
* Rückgabetype
* 0 - * Parameter
* 0 - * Übergabeparameter
* Methodenrumpf (Code der Ausgeführt wird)
* Methodenrumpf (Code der Ausgeführt wird)


==== Methodensignatur ====
==== Methodensignatur ====
Die '''Methodensignatur''' einer Methode, besteht aus '''Methodenname''', '''Übergabeparameter'''. Weiters muss die Signatur jeder '''Methode''' in einer [[{{PAGENAMEE}}#Klasse|Klasse]] eindeutig sein.<br>
Die '''Methodensignatur''' einer Methode, besteht aus '''Methodenname''' und '''Übergabeparameter'''. Weiters muss die Signatur jeder '''Methode''' in der '''Klasse''' in der sie definiert wurde eindeutig sein.<br>
Warum gehört der '''Rückgabetyp''' nicht zur '''Methodensignatur'''? Angenommen wir haben folgende [[{{PAGENAMEE}}#Klasse|Klasse]]:
Warum gehört der '''Rückgabetyp''' nicht zur '''Methodensignatur'''? Dies soll anhand von folgendem Beispiel illustriert werden:
<syntaxhighlight lang='java' line>
{{JML|code=
public class Calc {
public class Calc {
   public int add(float a, float b) {
   public int add(float a, float b) {
Zeile 130: Zeile 129:
   }
   }
}
}
</syntaxhighlight>
}}
In '''Java''' ist es nicht zwingend nötig den Rückgabewert einer Methode zu verarbeiten:
In '''Java''' ist es nicht zwingend nötig den '''Rückgabewert''' einer '''Methode''' zu verarbeiten:
<syntaxhighlight lang='java' line>
{{JML|code=
public static void main(String[] args) {
public static void main(String[] args) {
   Calc c = new Calc();
   Calc c = new Calc();
   c.add(10.0f, 20.0f);
   c.add(10.0f, 20.0f);
}
}
</syntaxhighlight>
}}
Der '''Compiler''' hat keine Möglichkeit herauszufinden, welche '''Methode''' in '''Calc''' nun verwendet werden soll. Deswegen gehört der '''Rückgabetyp''' nicht zur '''Methodensignatur''' und das Beispiel würde nicht compilieren.
Der '''Compiler''' hat keine Möglichkeit herauszufinden, welche '''Methode''' in {{JSL|Calc}} nun verwendet werden soll. Deswegen gehört der '''Rückgabetyp''' nicht zur '''Methodensignatur''' und das Beispiel würde nicht compilieren.


==== Instanzmethode ====
==== Instanzmethode ====
Folgendes Beispiel zeigt den klassischen '''getter''' und '''setter''', '''Attribute''' sollten nach Möglichkeit nur über diese geholt/verändert werden und die '''Attribute''' sollten nach außen hin nicht sichtbar sein ('''private'''). Warum? Durch den '''setter''' ist es möglich, eine inkorrekte Modifikation des '''Attributs''' zu unterbinden.
Folgendes Beispiel zeigt den klassischen '''getter''' und '''setter''', {{AL|Attribute}} sollten nach Möglichkeit nur über diese abgerufen und verändert werden und die {{AL|Attribute}} sollten nach außen hin nicht {{AL|Sichtbarkeit|sichtbar}} sein {{JSL|private}}. Warum? Durch den '''setter''' ist es möglich, eine inkorrekte Modifikation des '''Attributs''' zu unterbinden. Das heißt, es kann verhindert werden, dass ein {{AL|Attribute|Attribut}} auf einen Wert gesetzt wird, den es nicht annehmen sollte (z.B.: das Gewicht eines Tieres wird auf -10 gesetzt).
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   private String name;
   private String name;
Zeile 150: Zeile 149:
   }
   }


   public void getName(String name) {
   public String getName() {
     this.name = name;
     return this.name
   }
   }
}
}
Zeile 159: Zeile 158:
a.setName("Alfons");
a.setName("Alfons");
System.out.println(a.getName());
System.out.println(a.getName());
</syntaxhighlight>
}}


==== Klassenmethode ====
==== Klassenmethode ====
Eine klassische '''Helper''' Methode. Diese Methode wird über die Klasse selbst aufgerufen, sie existiert nur ein mal. Die Methode soll nicht über eine Instanz der Klasse aufgerufen werden.
'''Klassenmethoden''' werden oft verwendet, um Operationen zu realisieren die nicht direkt mit nur einer '''Instanz''' zu tun haben. Oftmals werden '''Helper Methoden''' so realisiert. Diese '''Methoden''' werden direkt über die '''Klasse''' selbst aufgerufen, sie existieren nur einmal. Es ist möglich, aber die '''Methode''' soll nicht über eine '''Instanz''' der '''Klasse''' aufgerufen werden. Weiters sei angemerkt, das '''Klassenmethoden''' oder '''statische Methoden''' durch {{AL|Vererbung}} nicht '''überschrieben''' werden können.
<syntaxhighlight lang='java' line>
{{JML|code=
public class Animal {
public class Animal {
   private float weight;
   private float weight;
Zeile 176: Zeile 175:
       weight += a.weight;
       weight += a.weight;
     }
     }
    return weight;
   }
   }
}
}
Zeile 185: Zeile 185:
animals.add(new Animal(30));
animals.add(new Animal(30));
System.out.println(Animal.calculateWeight(animals));
System.out.println(Animal.calculateWeight(animals));
</syntaxhighlight>
}}
 
== Objekt/Instanz VS. Klasse ==
Jede {{AL|Klasse}} erbt von {{JSL|java.lang.Object}}. Somit ist jede {{AL|Klasse}} ein {{JSL|java.lang.Object}}. Wenn jedoch von einem '''Objekt''' gesprochen wird, so meint man meist die '''Instanz''' einer {{AL|Klasse}}.


== Abstrakte Klasse ==
== Abstrakte Klasse ==
'''Abstrakte Klassen''' sind unfertige [[{{PAGENAMEE}}#Klasse|Klassen]]. Sie können nicht direkt '''instanziert''' werden. Es können nur '''Subklassen''' (Klassen die davon [[{{PAGENAMEE}}#Vererbung|erben]]) davon'''instanziert''' werden. Zusätzlich besteht die Möglichkeit eine '''Instanz''' durch eine '''Anonyme Implementierung''' der '''abstrakten Klasse''' zu erstellen.
'''Abstrakte Klassen''' sind unfertige {{AL|Klasse|Klassen}}. Sie können nicht direkt '''instanziert''' werden. Es können nur '''Subklassen''' ({{AL|Klasse|Klassen}} die davon {{AL|Vererbung|erben}}) '''instanziert''' werden. Zusätzlich besteht die Möglichkeit eine '''Instanz''' durch eine '''Anonyme Implementierung''' der '''abstrakten Klasse''' zu erstellen.
<br>Sie einzusetzen ist sinnvoll, wenn sich eine Gruppe von [[{{PAGENAMEE}}#Klasse|Klassen]] Funktionalität teilt, doch gewisse Funktionalität von jeder einzelnen [[{{PAGENAMEE}}#Klasse|Klasse]] implementiert werden muss.<br>
<br>Sie einzusetzen ist sinnvoll, wenn sich eine Gruppe von {{AL|Klasse|Klassen}} Funktionalität teilt, doch gewisse Funktionalität von jeder einzelnen {{AL|Klasse}} implementiert werden muss.<br>
Die noch zu implementierenden '''Methoden''' und die [[{{PAGENAMEE}}#Klasse|Klasse]] selbst werden mit dem Schlüsselwort '''abstract''' gekennzeichnet, .
Die noch zu implementierenden '''Methoden''' und die {{AL|Klasse}} selbst werden mit dem Schlüsselwort {{JSL|abstract}} gekennzeichnet.
<syntaxhighlight lang='java' line>
{{JML|code=
public abstract class Animal {
public abstract class Animal {
   private String name;
   private String name;
Zeile 203: Zeile 206:
   //Abstrakte Methode, muss implementiert werden
   //Abstrakte Methode, muss implementiert werden
   public abstract void eat();
   public abstract void eat();
  //Normale Methode
  public void sleep() {
    System.out.println("My name is: " + name + " and i sleep!");
  }
}
}


Zeile 232: Zeile 240:
Bird b = new Bird('Tweety');
Bird b = new Bird('Tweety');
b.eat();
b.eat();
//Folgendes ist auch möglich weil, durch die Vererbung, ein Bird ist ein Animal
//Folgendes ist auch möglich weil, durch die Vererbung, ein Bird ein Animal ist
Animal b1 = new Bird('Tweety');
Animal b1 = new Bird('Tweety');
b1.eat();
b1.eat();
Zeile 241: Zeile 249:
   }
   }
};
};
</syntaxhighlight>
}}


== Interface ==
== Interface ==
'''Interfaces''' oder auch '''Schnittstellen''' bieten die Möglichkeit Methoden zu definieren welche von Klassen die diese Schnittstelle implementieren, implementiert werden müssen. Der Vorteil von Schnittstellen gegenüber der '''Vererbung''' ist, dass eine [[{{PAGENAMEE}}#Klasse|Klasse]] mehrere '''Interfaces''' implementieren kann. Genauso wie bei der '''Abstrakten Klasse''' gilt, '''Interfaces''' können nicht direkt '''instanziert''' werden, eine '''Anonyme Implementierung''' ist jedoch möglich. Ein [[{{PAGENAMEE}}#Interface|Interface]] ist also eine Zusicherung dass eine [[{{PAGENAMEE}}#Klasse|Klasse]] eine gewisse Funktionalität beherrscht.
'''Interfaces''' oder auch '''Schnittstellen''' bieten die Möglichkeit {{AL|Methoden}} zu definieren welche von {{AL|Klasse|Klassen}} die diese '''Schnittstelle''' implementieren, implementiert werden müssen. Eine {{AL|Klasse}} implementiert eine '''Schnittstelle''' mittels des Schlüsselworts {{JSL|implements}}, weiters müssen dann noch die {{AL|Methoden}} überschrieben bzw implementiert werden. Der Vorteil von '''Schnittstellen''' gegenüber der '''Vererbung''' ist, dass eine {{AL|Klasse}} mehrere '''Interfaces''' implementieren kann. Genauso wie bei der {{AL|Abstrakte_Klasse|abstrakten Klasse}} gilt, '''Interfaces''' können nicht direkt '''instanziert''' werden, eine '''anonyme Implementierung''' ist jedoch möglich. Ein '''Interface''' ist also eine Zusicherung dass eine {{AL|Klasse}} eine gewisse Funktionalität beherrscht.
<syntaxhighlight lang='java' line>
{{JML|code=
public interface CanDrive {
public interface CanDrive {
   void drive();
   void drive();
Zeile 284: Zeile 292:
//Zuweisung ist möglich, da die Klasse Plane CanFly implementiert
//Zuweisung ist möglich, da die Klasse Plane CanFly implementiert
CanFly canFly = plane;
CanFly canFly = plane;
canFly.fly();
//Neues Auto wird instanziert
//Neues Auto wird instanziert
Car car = new Car();
Car car = new Car();
//Zuweisung ist möglich, da die Klasse Car CanDrive implementiert
//Zuweisung ist möglich, da die Klasse Car CanDrive implementiert
CanDrive canDrive = car;
CanDrive canDrive = car;
canDrive.drive();
//Neuer KnightRider wird instanziert
//Neuer KnightRider wird instanziert
KnightRider kit = new KnightRider();
KnightRider kitt = new KnightRider();
kitt.drive();
kitt.fly();
//Zuweisung ist möglich, da die Klasse KnightRider CanDrive implementiert
//Zuweisung ist möglich, da die Klasse KnightRider CanDrive implementiert
canDrive = kit;
canDrive = kitt;
canDrive.drive();
//Nicht möglich obwohl Kitt fliegen kann, aber die Variable hat den Typ CanDrive, dieser kann nicht fliegen
//canDrive.fly();
//Zuweisung ist möglich, da die Klasse KnightRider CanFly implementiert
//Zuweisung ist möglich, da die Klasse KnightRider CanFly implementiert
canFly = kit;
canFly = kitt;
</syntaxhighlight>
canFly.fly();
//Nicht möglich obwohl Kit fahren kann, aber die Variable hat den Typ CanFly, dieser kann nicht fahren
//canFly.drive();
}}


== Vererbung ==
== Vererbung ==
Bei der '''Vererbung''' gibt es immer zwei Protagonisten, die '''Subklasse''' und die '''Superklasse'''. Die '''Subklasse''' erbt von der '''Superklasse'''. Das heißt Sie übernimmt alle [[{{PAGENAMEE}}#Attribute|Attribute]] und alle [[{{PAGENAMEE}}#Methoden|Methoden]]. Die '''Instanz Methoden''' können auch überschrieben werden, wenn diese nicht mit dem Schlüsselwort '''final''' markiert wurden. Vererbung geschieht mittels des Schlüsselworts '''extends''', das heißt eine [[{{PAGENAMEE}}#Klasse|Klasse]] erweitert eine andere [[{{PAGENAMEE}}#Klasse|Klasse]]. In '''Java''' ist keine '''Mehrfachvererbung''' möglich!
Bei der '''Vererbung''' gibt es immer zwei Beteiligte, die '''Subklasse''' und die '''Superklasse'''. Die '''Subklasse''' erbt von der '''Superklasse'''. Das heißt Sie übernimmt alle {{AL|Attribute}} und alle {{AL|Methoden}}. Die '''Instanzmethoden''' können auch überschrieben werden, wenn diese nicht mit dem Schlüsselwort {{JSL|final}} markiert wurden. Vererbung geschieht mittels des Schlüsselworts {{JSL|extends}}, das heißt eine {{AL|Klasse}} erweitert eine andere {{AL|Klasse}}. In '''Java''' ist keine '''Mehrfachvererbung''' möglich. D.h. eine {{AL|Klasse}} kann nur von einer {{AL|Klasse}} erben.
  Die '''Superklasse''' kann entweder eine normale '''[[{{PAGENAMEE}}#Klasse|Klasse]]''' oder eine '''[[{{PAGENAMEE}}#Abstrakte_Klasse|Abstrakte Klasse]]''' sein. Von einem '''[[{{PAGENAMEE}}#Interface|Interface]]''', wird nicht geerbt, dieses wird implementiert.
  Die '''Superklasse''' kann entweder eine normale {{AL|Klasse}} oder eine {{AL|Abstrakte_Klasse|abstrakte Klasse}} sein. Von einem {{AL|Interface}} wird nicht geerbt, dieses wird '''implementiert'''.
 
{{JML|code=
<syntaxhighlight lang='java' line>
public class Animal {
public class Animal {
   private String name;
   private String name;
Zeile 329: Zeile 348:
   }
   }
}
}
</syntaxhighlight>
 
Folgendes ist wichtig bei der Vererbung zu erwähnen. Die '''Subklasse''' muss den '''Konstruktor''' der '''Superklasse''' aufrufen. Wenn es nur den '''Standard Konstruktor''' (keine Parameter) gibt, muss auch nicht '''super()''' aufgerufen werden.
public class Dog extends Animal {
  public Dog(String name) {
    //Der Konstruktor der Superklasse muss aufgerufen werden
    super(name);
  }
 
  @Override
  public void sayHello() {
    System.out.println("Hallo mein Name ist " + getName() + " und ich bin eine Dog!");
    //Aufruf der Methode in der Superklasse.
    super.sayHello();
  }
}
}}
Folgendes ist wichtig bei der Vererbung zu erwähnen. Die '''Subklasse''' muss den '''Konstruktor''' der '''Superklasse''' aufrufen, dies geschieht mittels {{JSL|super(...)}}. Wenn es nur den '''Standardkonstruktor''' (keine Parameter) gibt, muss {{JSL|super()}} nicht aufgerufen werden.
 
== Package ==
{{AL|Klasse|Klassen}} und {{AL|Interface|Interfaces}} sind in '''Java''' immer in '''Packages''' unterteilt. Diese dienen zum Gruppieren nach verschiedenen Zugehörigkeiten. Die '''Package''' Definition befindet sich immer bei der {{AL|Klasse}} oder dem {{AL|Interface}} ganz oben. Die Dateien werden intern in Ordnern abgelegt.
{{JML|code=
package at.drlue.matura;
 
public class Matura {
  public void printNote() {
    System.out.println("Eins");
  }
}
}}
Die {{AL|Klasse}} {{JSL|Matura}} befindet sich in der Datei '''Matura.java''', diese Datei befindet sich im Ordner '''at/drlue/matura/'''.


== Sichtbarkeit ==
== Sichtbarkeit ==
Zeile 337: Zeile 383:


'''Datei: at/drlue/matura/packageA/A.java'''
'''Datei: at/drlue/matura/packageA/A.java'''
<syntaxhighlight lang='java' line>
{{JML|code=public class A {
public class A {
   public String hi() {
   public String hi() {
     System.out.println("Hallo");
     System.out.println("Hallo");
Zeile 356: Zeile 401:
   }
   }
}
}
</syntaxhighlight>
}}
'''Datei: at/drlue/matura/packageB/B.java'''
'''Datei: at/drlue/matura/packageB/B.java'''
<syntaxhighlight lang='java' line>
{{JML|code=public class B {
public class B {
   private A a = new A();
   private A a = new A();


Zeile 381: Zeile 425:
   }
   }
}
}
</syntaxhighlight>
}}
'''Datei: at/drlue/matura/packageA/C.java'''
'''Datei: at/drlue/matura/packageA/C.java'''
<syntaxhighlight lang='java' line>
{{JML|code=public class C {
public class C {
   private A a = new A();
   private A a = new A();


Zeile 406: Zeile 449:
   }
   }
}
}
</syntaxhighlight>
}}
'''Datei: at/drlue/matura/packageD/D.java'''
'''Datei: at/drlue/matura/packageD/D.java'''
<syntaxhighlight lang='java' line>
{{JML|code=public class D extends A {
public class D extends A {
   private A a = new A();
   private A a = new A();


Zeile 431: Zeile 473:
   }
   }
}
}
</syntaxhighlight>
}}
 
== Casten ==
== Package ==
Mittels '''Casting''' können untereinander '''kompatible Datentypen''' umgewandelt werden.
[[{{PAGENAMEE}}#Klasse|Klassen]] und '''Interfaces''' sind in '''Java''' immer in '''Packages''' unterteilt. Diese dienen zum gruppieren nach verschiedenen zugehörigkeiten. Die '''Package''' Definition befindet sich immer bei der [[{{PAGENAMEE}}#Klasse|Klasse]] oder dem [[{{PAGENAMEE}}#Interface|Interface]] ganz oben. Die Dateien werden intern in Ordnern abelegt.
=== Casten von primitiven Datentypen ===
<syntaxhighlight lang='java' line>
{{Link|Primitive_Datentypen|Primitive Datentypen}} enthalten, werden Sie einer Variable zugewiesen, wirklich den Wert den Sie repräsentieren. Ein '''casten''' führt wirklich zu einem neuen Wert (verändert aber nicht den alten). Alle {{Link|Primitive_Datentypen|primitiven Datentypen}} können untereinander umgewandelt werden, außer {{JSL|boolean}}.
package at.drlue.matura;
{{JML|code=long a = 10;
 
public class Matura {
  public void printNote() {
    System.out.println("Eins");
  }
}
</syntaxhighlight>
Die Klasse '''Matura''' befindet sich in der Datei '''Matura.java''', diese Datei befindet sich im Ordner '''at/drlue/matura/'''.
 
== Weitere wichtige Dinge ==
Hier sollen noch einige Weitere Dinge abgeklärt werden.
 
=== Casten ===
Mittels '''Casting''' können untereinander kompatible Datentypen umgewandelt werden.
==== Casten von primitiven Datentypen ====
Primitive Datentypen enthalten werden Sie einer Variable zugewiesen, wirklich den Wert den Sie repräsentieren. Ein Casten führt wirklich zu einem neuen Wert (verändert aber nicht den alten). Alle primitiven Datentypen können untereinander umgewandelt werden, außer '''boolean'''.
<syntaxhighlight lang='java' line>
long a = 10;
//long wird in int umgewandelt
//long wird in int umgewandelt
int b = (int)a;
int b = (int)a;
//einem long kann aber ohne Casting ein int zugewiesen werden
//einem long kann aber ohne Casting ein int zugewiesen werden
a = b;
a = b;
</syntaxhighlight>
}}
==== Casten von Objekten ====
'''Objekte''' können nur in den Datentyp anderer kompatibler Klassen gecastet werden. Vereinfacht gesagt, es muss möglich sein, dass der Cast erfolgreich ist. Weiters ist hier zu erwähnen, dass keine Umwandlung der Daten erfolgt. Wird ein '''Objekt''' einer Variable zugewiesen, so ist dies '''nicht''' der Wert selbst, sondern nur eine '''Referenz''' darauf. Mit dem '''Cast''' wird nur das erwartete geändert, dass sich an der Stelle, an die diese Referenz zeigt.
<syntaxhighlight lang='java' line>
public class A {}


public class B {}
=== Casten von Objekten ===
'''Objekte''' können nur in den Datentyp anderer kompatibler {{AL|Klasse|Klassen}} '''gecastet''' werden. Vereinfacht gesagt, es muss möglich sein, dass der '''Cast''' erfolgreich ist. Weiters ist hier zu erwähnen, dass keine Umwandlung der Daten erfolgt. Wird ein '''Objekt''' einer Variable zugewiesen, so ist dies '''nicht''' der Wert selbst, sondern nur eine '''Referenz''' darauf. Mit dem '''Cast''' wird nur das erwartete geändert, dass sich an der Stelle befindet, an die diese Referenz zeigt.
{{JML|code=
public class Tier {}
 
public class Auto {}
...
...
public static void main(String[] args) {
public static void main(String[] args) {
   A a = new A();
   Tier a = new Tier();
   //Zuweisung nicht möglich, da A niemals ein B sein kann
   //Zuweisung nicht möglich, da A niemals ein B sein kann
   //B b = (B)a;
   //Auto b = (Auto)a;


   //Jede Klasse erbt von java.lang.Object kein Cast ist erforderlich da A ein Object ist
   //Jede Klasse erbt von java.lang.Object kein Cast ist erforderlich da A ein Object ist
   Object obj = a;
   Object obj = a;
   //Dieser Cast ist möglich, wir wissen zwar dass dies zu einer ClassCastException führt
   //Dieser Cast ist möglich, wir wissen zwar dass dies zu einer ClassCastException führt
   B b = (B) obj;
   Auto b = (Auto) obj;
}
}
</syntaxhighlight>
}}


== Exceptions ==
'''Exceptions''' oder '''Ausnahmen''' können von {{AL|Methoden}} und auch von {{Link|Konstruktor|Konstruktoren}} geworfen werden. Eine '''Exception''' tritt auf, wenn eine {{AL|Methoden}} außerhalb ihrer gewünschten Funktionalität operiert. Jede '''Exception''' ist ein {{JSL|java.lang.Throwable}}, d.h. Sie kann mittels des Schlüsselworts {{JSL|throw}} geworfen werden. Weiters unterscheiden wir zwei Arten von '''Exceptions'''.
=== Checked Exceptions ===
Dazu gehört jede '''Exception''' die von {{JSL|java.lang.Throwable}} erbt, aber keine {{JSL|java.lang.RuntimeException}} und kein {{JSL|java.lang.Error}} ist. Wenn '''Checked Exceptions''' geworfen werden, so muss dies in der {{AL|Methoden|Methode}} mittels {{JSL|throws ExceptionName}} deklariert werden. Zusätzlich muss die geworfene '''Exception''' auch immer von der Aufrufenden {{AL|Methoden|Methode}} behandelt, oder weitergeworfen, werden.
=== Unchecked Exceptions ===
Dazu gehören Alle '''Exceptions''' welche von {{JSL|java.lang.Error}} oder von {{JSL|java.lang.RuntimeException}} erben. Diese '''Exceptions''' müssen nicht in der {{Link|Methoden}} Definition deklariert werden. Sie können abgefangen und behandelt werden, ('''müssen sie aber nicht'''), normalerweise sollten diese aber überhaupt nicht auftreten.
{| class="wikitable"
|+ Beispiele für RuntimeExceptions
|-
! Klasse !! Code
|-
| {{JSL|java.lang.IndexOutOfBoundsException}} ||
{{JML|code=
int[] arr = new int[]{1,2,3,4};
//Index existiert nicht
System.out.println(arr[5]);
}}
|-
| {{JSL|java.lang.NullPointerException}} ||
{{JML|code=
Animal a = null;
//Die Referenz ist null, beim Zugriff crashts
System.out.println(a.toString());
}}
|}
{| class="wikitable"
|+ Beispiele für Errors
|-
! Klasse !! Code
|-
| {{JSL|java.lang.OutOfMemoryError}} ||
{{JML|code=
//Tritt auf wenn keine weiteren neuen Objekte mehr erstellt werden können
List<int[]> list = new LinkedList<>();
while(true) {
  list.add(new int[10000]);
}
}}
|}
=== Exceptions selbst definieren ===
Natürlich können auch eigene '''Exceptions''' erstellt werden. Sinnvoll ist dies, wenn die eigene '''Exception''' einen Mehrwert an Information liefert. Um eine eigene '''Exception''' zu erstellen wird einfach von '''Exception''' geerbt.
{{JML|code=
public class HttpStatusCodeException extends Exception {
  private int statusCode;
  private String url;
  public HttpStatusCodeException(int statusCode, String url) {
    //Text für die Exception wird erstellt
    super("Beim Aufruf von "+url+" ist ein Fehler mit dem Statuscode ["+statusCode+"] aufgetreten");
    this.statusCode = statusCode;
    this.url = url;
  }
  public int getStatusCode() {
    return statusCode;
  }
  public String getUrl() {
    return this.url;
  }
}
...
public static void main(String[] args) {
  try {
    executeRequest("https://drlue.at");
  } catch(HttpsStatusCodeException exc) {
    if(exc.getStatusCode() == 401) {
      login();
    }
  }
}
private static void executeRequest(String url) throws HttpStatusCodeException {
    Response resp = ...//network request
    if(!resp.isSuccessfull()) {
        throw new HttpStatusCodeException(resp.statusCode(), url);
    }
  }
}
}}
=== Beispiele ===
Im folgenden Beispiel wird eine {{Link|Methoden|Methode}} erstellt, welche einen Dateinamen nimmt und die Länge der Datei zurückgibt. Existiert die Datei nicht, so wird eine {{JSL|java.lang.FileNotFoundException}} geworfen:
{{JML|code=
public static long getFileLength(String fileName) throws FileNotFoundException {
  File f = new File(fileName);
  if(!f.exists()) {
    throw new FileNotFoundException();
  }
  return f.length();
}
}}
Die {{Link|Methoden|Methode}} können wir folgendermaßen verwenden, bei dieser Variante fangen wir die '''Exception''' ab:
{{JML|highlight='2,5-7'|code=
public static void main(String[] args) {
  try {
    long length = getFileLength("wichtig.txt");
    System.out.println("Die Datei ist: "+length+"Bytes lang");
  } catch(FileNotFoundException exc) {
    System.out.println("Die Datei wurde nicht gefunden!");
  }
}
}}
Eine weitere Variante ist, dass die Aufrufende {{Link|Methoden|Methode}}, die '''Exception''' weiter wirft.
{{JML|highlight='1'|code=
public static void main(String[] args) throws FileNotFoundException {
  long length = getFileLength("wichtig.txt");
  System.out.println("Die Datei ist: "+length+"Bytes lang");
}
}}
Es kann auch zuerst die '''Exception''' gefangen, und dann weitergeworfen werden.
Eine weitere Variante ist, dass die Aufrufende {{Link|Methoden|Methode}}, die '''Exception''' weiter wirft.
{{JML|highlight='2,5-8'|code=
public static void main(String[] args) throws FileNotFoundException {
  try {
    long length = getFileLength("wichtig.txt");
    System.out.println("Die Datei ist: "+length+"Bytes lang");
  } catch(FileNotFoundException exc) {
    System.out.println("Die Datei wurde nicht gefunden!");
    throw exc;
  }
}}
== Weitere wichtige Dinge ==
Hier sollen noch einige weitere Dinge abgeklärt werden.
=== Überladen von Methoden ===
=== Überladen von Methoden ===
Wir sprechen von überladen einer[[{{PAGENAMEE}}#Methode|Methode]], wenn mehrere Methoden in einer Klasse existieren und den den selben Namen haben, sich aber die Parameter, entweder in ihrem Datentyp, oder der Anzahl unterscheiden. Ein [[{{PAGENAMEE}}#Konstruktor|Konstruktor]] kann ebenfalls überladen werden.<br>
Wir sprechen von '''überladen''' einer {{AL|Methoden|Methode}}, wenn mehrere {{AL|Methoden}} in einer {{AL|Klasse}} existieren die den selben Namen haben, sich aber die '''Übergabeparameter''', entweder in ihrem Datentyp, oder der Anzahl unterscheiden. Ein {{Link|Konstruktor}} kann ebenfalls überladen werden.<br>
Im folgenden Beispiel wird die Methode ''add'' überladen. Der '''Compiler''' entscheidet anhand des Datentyps der Parameter welche Methode verwendet werden soll, '''der Rückgabetyp spielt keine Rolle.'''
Im folgenden Beispiel wird die {{AL|Methoden|Methode}} {{JSL|add(...)}} überladen. Der '''Compiler''' entscheidet anhand des Datentyps der Parameter welche {{AL|Methoden|Methode}} verwendet werden soll, '''der Rückgabetyp spielt keine Rolle.'''
<syntaxhighlight lang='java' line>
{{JML|code=
public class Calc {
public class Calc {
   public int add(int a, int b) {
   public int add(int a, int b) {
Zeile 500: Zeile 653:
   float a = c.add(3, 2);  
   float a = c.add(3, 2);  
}
}
</syntaxhighlight>
}}


=== Polymorphismus ===
=== Polymorphismus ===
'''Polymorphismus''' oder Vielgestaltigkeit, beschreibt den Vorgang bei einem Methodenaufruf auf eine '''Instanz''' einer '''Subklasse'''. Eine Methode ist '''Polymorph''' wenn diese in verschiedenen Klassen die selbe Signatur aufweist.
'''Polymorphismus''' oder '''Vielgestaltigkeit''' beschreibt den Sachverhalt, wenn ein '''Objekt''' des Typs {{JSL|A}} vorhanden ist, in Wirklichkeit ein {{JSL|B}} sein kann (natürlich nur wenn {{JSL|B}} von {{JSL|A}} {{Link|Vererbung|erbt}} bzw. {{JSL|A}} '''implementiert''', ansonsten kann das nicht sein). Die '''Vielgestaltigkeit''' bezieht sich somit auf das Aufrufen von {{AL|Methoden}}. Wird eine Methode von {{JSL|A}} aufgerufen, so kann dies in Wirklichkeit die {{AL|Methoden|Methode}} in {{JSL|B}} aufrufen, wenn {{JSL|B}} diese überschreibt. Eine Methode ist '''Polymorph''' wenn diese in der '''Subklasse''' die selbe {{Link|Methodensignatur}} aufweist wie in der '''Superklasse'''.
<syntaxhighlight lang='java' line>
{{JML|code=
public class A {
public class A {
   public void doSomething() {
   public void doSomething() {
Zeile 519: Zeile 672:
...
...
public static void main(String[] args) {
public static void main(String[] args) {
   doSomething(new B());
   reallyDoSomething(new B());
}
}


Zeile 525: Zeile 678:
   a.doSomething();
   a.doSomething();
}
}
</syntaxhighlight>
}}
Obwohl in der Methode <syntaxhighlight lang='java' inline>reallyDoSomething(A a)</syntaxhighlight> eine '''Instanz''' des Typs '''A''' als Parameter erwartet wird, ist es in Wirklichkeit eine '''Instanz''' des Typs '''B'''. Ein Aufruf von  <syntaxhighlight lang='java' inline>a.doSomething()</syntaxhighlight> führt nicht den Code in '''Klasse A''' sondern '''Klasse B''' aus.
Obwohl in der Methode {{JSL|reallyDoSomething(A a)}} eine '''Instanz''' von {{JSL|A}} als Parameter erwartet wird, ist es in Wirklichkeit eine '''Instanz''' von {{JSL|B}}. Ein Aufruf von  {{JSL|a.doSomething()}} führt nicht den Code in {{JSL|A}} sondern den Code in {{JSL|B}} aus, da {{JSL|doSomething()}} in {{JSL|B}} überschrieben wurde.


=== Beziehungen ===
=== Beziehungen ===
Hier sollen noch die Beziehungen zwischen [[{{PAGENAMEE}}#Klasse|Klassen]] bzw. '''Objekten''' geklärt werden.
Hier sollen noch die Beziehungen zwischen [[{{PAGENAMEE}}#Klasse|Klassen]] bzw. '''Objekten''' geklärt werden.
==== Is A ====
==== Is A ====
Wenn eine '''Klasse Cat''' eine '''Klasse Animal''' erweitert, d.h. von ihr erbt. Somit ist '''Cat''' ein '''Animal''' und die folgende Zuweisung ist möglich:
Wenn eine {{AL|Klasse}} {{JSL|Cat}} eine {{AL|Klasse}} {{JSL|Animal}} erweitert, d.h. von ihr {{Link|Vererbung|erbt}}. Somit '''ist''' {{JSL|Cat}} ein {{JSL|Animal}} und die folgende Zuweisung ist möglich:
<syntaxhighlight lang='java' line>
{{JML|code=
Cat cat = new Cat();
Cat cat = new Cat();
Animal animal = cat;
Animal animal = cat;
</syntaxhighlight>
}}
Umgekehrt ist das nicht zwingend so. Wenn ich ein '''Objekt''' vom Typ '''Animal''' habe, so könnte es ein '''Object''' vom Type '''Cat''' sein, muss es aber nicht. Um dies zu prüfen gibt es das Schlüsselwort '''instanceof''' und es kann ein [[{{PAGENAMEE}}#Cast|Cast]] erfolgen. Die Umwandlung ist auch ohne Prüfung möglich, dies kann jedoch zu Abstürzen durch eine '''ClassCastException''' führen.
Umgekehrt ist das nicht zwingend so. Wenn ein '''Objekt''' vom Typ {{JSL|Animal}} vorhanden ist, so könnte es ein '''Objekt''' vom Typ {{JSL|Cat}} sein, muss es aber nicht. Um dies zu prüfen gibt es das Schlüsselwort {{JSL|instanceof}} und es kann ein {{Link|Casten|Cast}} erfolgen. Die Umwandlung ist auch ohne Prüfung möglich, dies kann jedoch zu Abstürzen durch eine {{JSL|java.lang.ClassCastException}} führen.
<syntaxhighlight lang='java' line>
{{JML|code=
public void doSomething(Animal animal) {
public void doSomething(Animal animal) {
   if(animal instanceof Cat) {
   if(animal instanceof Cat) {
Zeile 546: Zeile 699:
   }
   }
}
}
</syntaxhighlight>
}}
Das selbe gilt genau gleich, wenn eine [[{{PAGENAMEE}}#Klasse|Klasse]] ein [[{{PAGENAMEE}}#Interface|Interface]] implementiert.<br>
Das selbe gilt genau gleich, wenn eine {{AL|Klasse}} ein {{AL|Interface}} implementiert.<br>
'''Is A''' ist somit erweiterung einer [[{{PAGENAMEE}}#Klasse|Klasse]] oder Implementierung einer [[{{PAGENAMEE}}#Interface|Schnittstelle]]. Es handelt sich hierbei um eine '''starke Bindung''', d.h. diese kann zur Laufzeit des Programmes '''nicht''' verändert werden.
'''Is A''' ist somit eine Erweiterung einer {{AL|Klasse}}, oder eine Implementierung einer {{AL|Interface|Schnittstelle}}.
Es handelt sich hierbei um eine '''starke Bindung''', d.h. diese kann zur Laufzeit des Programmes '''nicht''' verändert werden.


==== Has A ====
==== Has A ====
Eine '''Has A''' Beziehung wird auch '''Komposition''' oder '''Zusammenstellung''' genannt. '''Komposition''' ist eine '''schwache Bindung'''. Sie kann während der Laufzeit des Programmes verändert werden. Folgendes Beispiel soll eine '''Has A''' Beziehung verdeutlichen:
Eine '''Has A''' Beziehung wird auch '''Komposition''' oder '''Zusammenstellung''' genannt. '''Komposition''' ist eine '''schwache Bindung'''. Sie kann während der Laufzeit des Programmes verändert werden. Folgendes Beispiel soll eine '''Has A''' Beziehung verdeutlichen:
<syntaxhighlight lang='java' line>
{{JML|code=
public class Cat {
public class Cat {
   private List<Spielzeug> spielzeuge = new ArrayList();
   private List<Spielzeug> spielzeuge = new ArrayList();
Zeile 578: Zeile 732:
   cat.removeSpielzeug(ball);
   cat.removeSpielzeug(ball);
}
}
</syntaxhighlight>
}}
Hier wird gezeigt, dass Objekten zur Laufzeit andere Objekte hinzugefügt und entfernt werden können.
Hier wird gezeigt, dass '''Objekten''' zur Laufzeit andere '''Objekte''' hinzugefügt und entfernt werden können.
'''Has A''' Beziehung ist eine schwache Bindung.


== Multithreading ==
== Multithreading ==
'''Threading''' oder '''Nebenläufigkeit''' bezeichnet den Vorgang in einem Programm das unterschiedliche Handlungsstränge aufweist. D.h. verschieden Programmabläufe laufen parallel. Diese Parallelität kann wirklich parallel ablaufen, d.h. 2 oder mehr '''CPUs''' sind involviert, oder es kann nur pseudoparallel Ablaufen, zwischen den unterschiedlichen Abläufen wird sehr schnell hin und her gewechselt. Je nach implementierung der '''Java''' '''V'''irtual '''M'''achine, läuft es wirklich parallel oder nur pseudo parallel ('''green Threads''').  Folgendes Beispiel soll einen parallelen Ablauf verdeutlichen:
'''Threading''' oder '''Nebenläufigkeit''' bezeichnet den Vorgang in einem Programm das unterschiedliche Handlungsstränge aufweist. D.h. verschiedene Programmabläufe laufen parallel. Diese Parallelität kann wirklich parallel ablaufen, d.h. 2 oder mehr '''CPUs''' sind involviert, oder es kann pseudo parallel Ablaufen, zwischen den unterschiedlichen Abläufen wird sehr schnell hin und her gewechselt, aber alles läuft auf einer '''CPU'''. Je nach Implementierung der '''J'''ava '''V'''irtual '''M'''achine läuft es wirklich parallel oder nur pseudo parallel ('''green Threads''').  Folgendes Beispiel soll einen parallelen Ablauf verdeutlichen:
<syntaxhighlight lang='java' line>
{{JML|code=
public static void main(String[] args) {
public static void main(String[] args) {
   Thread a = new Thread(new Runnable() {
   Thread a = new Thread(new Runnable() {
Zeile 610: Zeile 765:
   b.start();
   b.start();
}
}
</syntaxhighlight>
}}
Zuerst werden die '''Threads''' erstellt, diesen wird ein '''Objekt''' des Typs '''java.lang.Runnable''' mitgegeben. Alternative kann auch eine [[{{PAGENAMEE}}#Klasse|Klasse]] erstellt werden, welche von '''java.lang.Thread''' erbt und die '''run() Methode''' überschreibt. Nach dem initialisieren, können die '''Thread''' Instanzen mittels '''start()''' gestartet werden, '''run()''' wird nun jeweils in einem anderen '''Thread''' aufgerufen.
Zuerst werden die '''Threads''' erstellt, diesen wird ein '''Objekt''' des Typs {{JSL|java.lang.Runnable}} mitgegeben. Alternativ kann auch eine {{AL|Klasse}} erstellt werden, welche von {{JSL|java.lang.Thread}} erbt und die {{JSL|run()}} {{AL|Methoden|Methode}} überschreibt. Nach dem initialisieren, können die {{JSL|Thread}} '''Instanzen''' mittels {{JSL|start()}} gestartet werden, {{JSL|run()}} wird nun jeweils in einem anderen '''Thread''' aufgerufen, der Ablauf ist dadurch ''parallel'', also ''gleichzeitig''.
 
=== Thread safety ===
Wenn eine {{AL|Klasse}} bzw. der {{AL|Methoden}} ohne Einschränkung aus mehreren '''Threads''' verwendet werden kann, so spricht man von '''Thread safety''', also eine {{AL|Methode}} oder eine {{AL|Klasse}} ist '''Thread safe'''. Ist sie dies nicht, so kann es zu unerwünschtem Verhalten oder auch zu {{Link|Exceptions}} führen.<br><br>
Folgender Code verwendet die '''nicht Thread sichere Klasse''' {{JSL|java.util.ArrayList}}. Am Ende der Ausführung ist ersichtlich, dass nicht die gewünschte Anzahl an Elementen in die Liste Eingetragen wurde. Mit etwas glück, tritt sogar eine {{Link|Exceptions|Exception}} auf, wenn die Liste im einen '''Thread''' gerade vergrößert werden muss, und der andere '''Thread''' ein Element einfügen will:
{{JML|code=
import java.util.ArrayList;
import java.util.List;
 
public class ThreadSafetyTest {
  public static void main(String[] args) throws InterruptedException {
    List<String> list = new ArrayList<>(); //Not thread safe
 
    Thread a = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };
 
    Thread b = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };
 
    a.start();
    b.start();
 
    a.join();
    b.join();
 
    System.out.println(list.size());
  }
}
}}
Nachfolgender Code verwendet die '''Thread sichere Klasse''' {{JSL|java.util.Vector}}, das Ergebnis ist nun korrekt:
{{JML|code=
import java.util.List;
import java.util.Vector;
 
public class ThreadSafetyTest2 {
  public static void main(String[] args) throws InterruptedException {
    List<String> list = new Vector<>(); //Thread safe
 
    Thread a = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };
 
    Thread b = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };
 
    a.start();
    b.start();
 
    a.join();
    b.join();
 
    System.out.println(list.size());
  }
}
}}


=== Synchronisierung ===
=== Synchronisierung ===
Verwendet ein Programm mehrere '''Threads''' so kann dies oft zu Problemen führen, wenn '''kritische Bereiche''' welche '''nicht atomare Operationen''' enthalten gleichzeitig verwendet werden.
Verwendet ein Programm mehrere '''Threads''' so kann dies zu Problemen führen, wenn '''kritische Bereiche''', welche '''nicht atomare Operationen''' enthalten gleichzeitig verwendet werden.
  Atomare Operationen sind nicht Teilbar. Eine int Variable zu erhöhen ist Teilbar.<br>
  Atomare Operationen sind nicht Teilbar. Eine int Variable zu erhöhen ist Teilbar.<br>
  1) Nimm die Zahl und erhöhe sie um 1
  1) Nimm die Zahl und erhöhe sie um 1
  2) Überschreibe den Speicherbereich der Zahl
  2) Überschreibe den Speicherbereich der Zahl
<syntaxhighlight lang='java' line>
{{JML|code=
private static int count = 0;
private static int count = 0;


Zeile 652: Zeile 880:
   System.out.println("Difference: "+(2000 - count));
   System.out.println("Difference: "+(2000 - count));
}
}
</syntaxhighlight>
}}
In diesem Beispiel ist ersichtlich, dass die Variable am Ende nicht ''2000'' ist, aufgrund dieser '''nicht atomaren''' Erhöhung der Zahl um 1.<br>
In diesem Beispiel ist ersichtlich, dass die Variable am Ende nicht ''2000'' ist, aufgrund dieser '''nicht atomaren''' Erhöhung der Zahl um 1.<br>
Um '''nicht atomare Bereiche''' sicher zu machen, kann das Schlüsselwort '''synchronized''' verwendet werden. '''synchronized''' verwendet ein sogenanntes '''Object Lock''' um einen bereich abzusichern, beim betreten wird es geholt, beim Verlassen zurückgegeben. Dieses '''Lock''' existiert bei jedem '''Objekt''' nur einmal. Kann es nicht geholt werden, so muss gewartet werden, bevor der geschützte bereich verwendet werden darf.
Um '''nicht atomare Bereiche''' sicher zu machen, kann das Schlüsselwort {{JSL|synchronized}} verwendet werden. {{JSL|synchronized}} verwendet ein sogenanntes '''Object Lock''' um einen kritischen Bereich abzusichern. Beim Betreten wird dieses geholt, beim Verlassen zurückgegeben. Dieses '''Lock''' existiert bei jedem '''Objekt''' nur einmal. Kann es nicht geholt werden, so wird gewartet bis es verfügbar ist und erst dann wird der geschützte Bereich betreten.
{| class="wikitable"
{| class="wikitable"
|+ Wie kann '''synchronized''' verwendet werden
|+ Wie kann {{JSL|synchronized}} verwendet werden
|-
|-
! Code !! Beschreibung
! Code !! Beschreibung
|-
|-
|
|
<syntaxhighlight lang='java' line>
{{JML|code=
synchronized(object) {
synchronized(object) {
   //kritischer Bereich
   //kritischer Bereich
}
}
</syntaxhighlight>
}}
|| Das '''Lock''' wird von einem bestimmten '''Object''' geholt.
|| Das '''Lock''' wird von einem bestimmten '''Object''' geholt.
|-
|-
|
|
<syntaxhighlight lang='java' line>
{{JML|code=
public synchronized void doSomething() {
public synchronized void doSomething() {
   //kritischer Bereich
   //kritischer Bereich
}
}
</syntaxhighlight>
}}
|| Das '''Lock''' wird von der '''Instanz''' geholt, zu der dieser '''Methodenaufruf''' gehört.
|| Das '''Lock''' wird von der '''Instanz''' geholt, zu der dieser '''Methodenaufruf''' gehört.
|-
|-
|
|
<syntaxhighlight lang='java' line>
{{JML|code=
public static synchronized void doSomething() {
public static synchronized void doSomething() {
   //kritischer Bereich
   //kritischer Bereich
}
}
</syntaxhighlight>
}}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{{Space30}}{{Space30}}{{Space30}}{{Space30}}
|| Synchronized kann auch bei '''statischen Methoden''' verwendet werden. Das '''Lock''' wird von der [[{{PAGENAMEE}}#Klasse|Klasse]] selbst geholt. Die geladene Klasse ist ebenfalls eine Instanz (von der eigenen Definition), diese existiert aber nur einmal.
|| Synchronized kann auch bei '''statischen Methoden''' verwendet werden. Das '''Lock''' wird von der {{AL|Klasse}} selbst geholt. Die geladene {{AL|Klasse}} ist ebenfalls eine Instanz (von der eigenen Definition), diese existiert aber nur einmal.
|}
|}
Somit kann das oben genannte Beispiel gelöst werden:
Somit kann das oben genannte Beispiel gelöst werden:
<syntaxhighlight lang='java' line>
{{JML|code=
private static int count = 0;
private static int count = 0;


Zeile 724: Zeile 952:
   System.out.println("Difference: "+(2000 - count));
   System.out.println("Difference: "+(2000 - count));
}
}
</syntaxhighlight>
}}

Aktuelle Version vom 10. März 2021, 10:32 Uhr

Die objektorientierte Programmierung (kurz OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft. Ein Modell dieser Strukturen wird in der Entwurfsphase aufgestellt. Es enthält Informationen über die auftretenden Objekte und deren Abstraktionen, ihre Typen. Die Umsetzung dieser Denkweise erfordert die Einführung verschiedener Konzepte, insbesondere Klassen, Vererbung, Polymorphie und spätes Binden (dynamisches Binden).[1]

Java

Java ist eine objektorientierte Programmiersprache. In einigen Punkten nimmt Sie die Objektorientierung nicht so streng wie andere Sprachen. Ein Beispiel hierfür wären die primitiven Datentypen. Somit ist in Java nicht alles ein Objekt (Was ist ein Objekt?) .

Primitive Datentypen

In Java gibt es eine vielzahl von primitiven Datentypen. Sie unterscheiden sich darin, dass Sie kein Objekt sind. Sie haben keine Methoden und auch keine Attribue. Wird eine Variable mit einem primitiven Datentyp erstellt und dieser Variable ein Wert zugewiesen, so enthält diese Variable den wirklichen Wert und nicht nur eine Referenz auf das eigentliche Objekt:

//Variable a enthält den Wert 10
int a = 10;
//Variable b enthält nur den Verweis auf das Integer Objekt mit dem Wert 10
Integer b = Integer.valueOf(10);

Zu jedem primitiven Datentyp gibt es eine entsprechende Klasse:

Entsprechende Klasse für primitive Datentypen
primitiver Datentyp Klasse/Komplexer Datentyp Beschreibung
int java.lang.Integer Ganzzahl in Zweierkomplent Darstellung, max: 231-1, min: -231
long java.lang.Long Ganzzahl in Zweierkomplent Darstellung, max: 263-1, min: -263
float java.lang.Float Fließkommazahl
double java.lang.Double Fließkommazahl mit doppelter Genauigkeit
char java.lang.Character Einzelnes Zeichen
boolean java.lang.Boolean Wahrheitswert, true oder false

Primitive Datentypen können automatisch in ihr entsprechendes Klassenäquivalent (in ein Objekt) umgewandelt werden und natürlich umgekehrt. Dieser Prozess nennt sich Autoboxing. Dies ist vor allem von Vorteil, wenn mit Collections (Listen,...) gearbeitet wird, da diese nur mit Objekten funktionieren.

//Umwandlung der Zahl 10 in ein Integer Object
Integer b = 10;
//Integer Object wird in primitive Zahl 10 umgewandelt
int c = b;

Klasse

Unter einer Klasse (auch Objekttyp genannt) versteht man in der objektorientierten Programmierung ein abstraktes Modell bzw. einen Bauplan für eine Reihe von ähnlichen Objekten. Die Klasse dient als Bauplan für die Abbildung von realen Objekten in Softwareobjekte und beschreibt Attribute (Eigenschaften) und Methoden (Verhaltensweisen) der Objekte. Verallgemeinernd könnte man auch sagen, dass eine Klasse dem Datentyp eines Objekts entspricht.[2]
Wir sehen, eine Klasse kann man sich wie eine Vorlage vorstellen, aus dieser dann Instanzen bzw. Objekte mittels des Schlüsselworts new erstellt werden. Weiters sei erwähnt, dass jede Klasse egal ob es hingeschrieben wird oder nicht, von der Java Klasse java.lang.Object erbt.

Konstruktor

Jede Klasse hat einen Konstruktor, ist dieser leer, d.h. er nimmt keine Parameter, muss dieser nicht geschrieben werden. Der Konstruktor heißt immer gleich wie die Klasse selbst.

public class Animal {
  private String name;

  //Standardkonstruktor wird verwendet.
}
...
//Instanz von Animal erstellen
Animal a = new Animal();

Wollen wir nun beispielsweise garantieren, dass ein Animal bei der Instanzierung einen Namen hat, so könnten wir den Konstruktor verändern.

public class Animal {
  private String name;

  public Animal(String name) {
    this.name = name;
  }
}
...
//Instanz von Animal erstellen
Animal a = new Animal("Alfons");

Es können auch mehrere Konstruktoren existieren. Diese können sich auch gegenseitig aufrufen. Sobald ein Konstruktor definiert wird, so kann der Standardkonstruktor nicht mehr zur Instanzierung verwendet werden. Soll der Standardkonstruktor weiter verfügbar sein, so muss dieser explizit hingeschrieben werden. Haben wir mehrere Konstruktoren so können wir auch von Konstruktor Überladung sprechen.

public class Animal {
  private String name;

  public Animal() {
    this("John Doe")
  }

  public Animal(String name) {
    this.name = name;
  }
}
...
//Instanz von Animal erstellen
Animal a = new Animal(); //John Doe
//Weitere Instanz mit gewähltem Namen
Animal b = new Animal("Alfons"); //Alfons

Attribute

Klassen haben Attribute (Eigenschaften). Hier werden zwei Varianten von Attributen unterschieden. Instanzattribute und Klassenattribute.

Instanzattribut

public class Animal {
  public String name;
}
...
//Korrekter Zugriff
Animal a = new Animal();
System.out.println(a.name);

Jede Instanz einer Klasse verfügt über eigene Instanzattribute, diese werden nicht untereinander geteilt. Das heißt, gibt es mehrere Instanzen der selben Klasse, so haben die Instanzattribute unterschiedliche Werte.

Klassenattribut

public class Animal {
  public static double PI = 3.14;
}
//Korrekter Zugriff
System.out.println(Animal.PI);

Attribute die mit dem Schlüsselwort static gekennzeichnet werden, existieren nur einmal. Vereinfacht gesagt, diese Attribute sind an die Klasse und nicht an die Instanz gebunden.

Methoden

Methoden sind Abläufe oder Verhaltensweisen die in Klassen definiert werden. Durch Methoden können Objekte miteinander interagieren, bzw. deren Zustand kann modifiziert werden. Genauso wie bei den Attributen können Methoden für eine Instanz mit dem Schlüsselwort static für die Klasse definiert werden.

Methoden haben zumindest:

  • Methodennamen
  • Rückgabetype
  • 0 - * Übergabeparameter
  • Methodenrumpf (Code der Ausgeführt wird)

Methodensignatur

Die Methodensignatur einer Methode, besteht aus Methodenname und Übergabeparameter. Weiters muss die Signatur jeder Methode in der Klasse in der sie definiert wurde eindeutig sein.
Warum gehört der Rückgabetyp nicht zur Methodensignatur? Dies soll anhand von folgendem Beispiel illustriert werden:

public class Calc {
  public int add(float a, float b) {
    return (int) (a + b);
  }

  public float add(float a, float b) {
    return a + b;
  }
}

In Java ist es nicht zwingend nötig den Rückgabewert einer Methode zu verarbeiten:

public static void main(String[] args) {
  Calc c = new Calc();
  c.add(10.0f, 20.0f);
}

Der Compiler hat keine Möglichkeit herauszufinden, welche Methode in Calc nun verwendet werden soll. Deswegen gehört der Rückgabetyp nicht zur Methodensignatur und das Beispiel würde nicht compilieren.

Instanzmethode

Folgendes Beispiel zeigt den klassischen getter und setter, Attribue sollten nach Möglichkeit nur über diese abgerufen und verändert werden und die Attribue sollten nach außen hin nicht sichtbar sein private. Warum? Durch den setter ist es möglich, eine inkorrekte Modifikation des Attributs zu unterbinden. Das heißt, es kann verhindert werden, dass ein Attribut auf einen Wert gesetzt wird, den es nicht annehmen sollte (z.B.: das Gewicht eines Tieres wird auf -10 gesetzt).

public class Animal {
  private String name;

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

  public String getName() {
    return this.name
  }
}
...
//Korrekter Aufruf
Animal a = new Animal();
a.setName("Alfons");
System.out.println(a.getName());

Klassenmethode

Klassenmethoden werden oft verwendet, um Operationen zu realisieren die nicht direkt mit nur einer Instanz zu tun haben. Oftmals werden Helper Methoden so realisiert. Diese Methoden werden direkt über die Klasse selbst aufgerufen, sie existieren nur einmal. Es ist möglich, aber die Methode soll nicht über eine Instanz der Klasse aufgerufen werden. Weiters sei angemerkt, das Klassenmethoden oder statische Methoden durch Vererbung nicht überschrieben werden können.

public class Animal {
  private float weight;

  public Animal(float weight) {
    this.weight = weight;
  }

  public static float calculateWeight(List<Animal> animals) {
    float weight = 0;
    for(Animal a : animal) {
      weight += a.weight;
    }
    return weight;
  }
}
...
//Korrekter Aufruf
List<Animal> animals = new ArrayList<>();
animals.add(new Animal(10));
animals.add(new Animal(20));
animals.add(new Animal(30));
System.out.println(Animal.calculateWeight(animals));

Objekt/Instanz VS. Klasse

Jede Klasse erbt von java.lang.Object. Somit ist jede Klasse ein java.lang.Object. Wenn jedoch von einem Objekt gesprochen wird, so meint man meist die Instanz einer Klasse.

Abstrakte Klasse

Abstrakte Klassen sind unfertige Klassen. Sie können nicht direkt instanziert werden. Es können nur Subklassen (Klassen die davon erben) instanziert werden. Zusätzlich besteht die Möglichkeit eine Instanz durch eine Anonyme Implementierung der abstrakten Klasse zu erstellen.
Sie einzusetzen ist sinnvoll, wenn sich eine Gruppe von Klassen Funktionalität teilt, doch gewisse Funktionalität von jeder einzelnen Klasse implementiert werden muss.
Die noch zu implementierenden Methoden und die Klasse selbst werden mit dem Schlüsselwort abstract gekennzeichnet.

public abstract class Animal {
  private String name;
  private float weight;

  public Animal(String name, String weight) {
    this.name = name;
    this.weight = weight;
  }

  //Abstrakte Methode, muss implementiert werden
  public abstract void eat();

  //Normale Methode
  public void sleep() {
    System.out.println("My name is: " + name + " and i sleep!");
  }
}

public class Cat extends Animal {
  public Animal(String name, String weight) {
    //Konstruktor der Superklasse muss aufgerufen werden
    super(name, weight);
  }

  @Override
  public void eat() {
    System.out.println("I eat mice!");
  }
}

public class Bird extends Animal {
  public Animal(String name, String weight) {
    //Konstruktor der Superklasse muss aufgerufen werden
    super(name, weight);
  }

  @Override
  public void eat() {
    System.out.println("I eat worms!");
  }
}
...
//Instanzierung
Bird b = new Bird('Tweety');
b.eat();
//Folgendes ist auch möglich weil, durch die Vererbung, ein Bird ein Animal ist
Animal b1 = new Bird('Tweety');
b1.eat();
//Anonyme Implementierung
Animal a = new Animal("Anonymous", 30) {
  public void eat() {
    System.out.println("I eat nothing.");
  }
};

Interface

Interfaces oder auch Schnittstellen bieten die Möglichkeit Methoden zu definieren welche von Klassen die diese Schnittstelle implementieren, implementiert werden müssen. Eine Klasse implementiert eine Schnittstelle mittels des Schlüsselworts implements, weiters müssen dann noch die Methoden überschrieben bzw implementiert werden. Der Vorteil von Schnittstellen gegenüber der Vererbung ist, dass eine Klasse mehrere Interfaces implementieren kann. Genauso wie bei der abstrakten Klasse gilt, Interfaces können nicht direkt instanziert werden, eine anonyme Implementierung ist jedoch möglich. Ein Interface ist also eine Zusicherung dass eine Klasse eine gewisse Funktionalität beherrscht.

public interface CanDrive {
  void drive();
}

public interface CanFly {
  void fly();
}

public class Car implements CanDrive {
  @Override
  public void drive() {
    System.out.println("Driving on the road");
  }
}

public class Plane implements CanFly {
  @Override
  public void fly() {
    System.out.println("Flying in the sky");
  }
}

public class KnightRider implements CanDrive, CanFly {
  @Override
  public void drive() {
    System.out.println("Driving on the road");
  }

  @Override
  public void fly() {
    System.out.println("Flying in the sky");
  }
}
...
//Neues Flugzeug wird instanziert
Plane plane = new Plane();
//Zuweisung ist möglich, da die Klasse Plane CanFly implementiert
CanFly canFly = plane;
canFly.fly();

//Neues Auto wird instanziert
Car car = new Car();
//Zuweisung ist möglich, da die Klasse Car CanDrive implementiert
CanDrive canDrive = car;
canDrive.drive();

//Neuer KnightRider wird instanziert
KnightRider kitt = new KnightRider();
kitt.drive();
kitt.fly();
//Zuweisung ist möglich, da die Klasse KnightRider CanDrive implementiert
canDrive = kitt;
canDrive.drive();
//Nicht möglich obwohl Kitt fliegen kann, aber die Variable hat den Typ CanDrive, dieser kann nicht fliegen
//canDrive.fly();
//Zuweisung ist möglich, da die Klasse KnightRider CanFly implementiert
canFly = kitt;
canFly.fly();
//Nicht möglich obwohl Kit fahren kann, aber die Variable hat den Typ CanFly, dieser kann nicht fahren
//canFly.drive();

Vererbung

Bei der Vererbung gibt es immer zwei Beteiligte, die Subklasse und die Superklasse. Die Subklasse erbt von der Superklasse. Das heißt Sie übernimmt alle Attribue und alle Methoden. Die Instanzmethoden können auch überschrieben werden, wenn diese nicht mit dem Schlüsselwort final markiert wurden. Vererbung geschieht mittels des Schlüsselworts extends, das heißt eine Klasse erweitert eine andere Klasse. In Java ist keine Mehrfachvererbung möglich. D.h. eine Klasse kann nur von einer Klasse erben.

Die Superklasse kann entweder eine normale Klasse oder eine abstrakte Klasse sein. Von einem Interface wird nicht geerbt, dieses wird implementiert.
public class Animal {
  private String name;

  public Animal(String name) {
    this.name = name;
  }

  //Kann nicht überschrieben werden
  public final String getName() {
    return this.name
  }

  public void sayHello() {
    System.out.println("Hallo, ich bin " + name);
  }
}

public class Cat extends Animal {
  public Cat(String name) {
    //Der Konstruktor der Superklasse muss aufgerufen werden
    super(name);
  }

  @Override
  public void sayHello() {
    System.out.println("Hallo mein Name ist " + getName() + " und ich bin eine Katze!");
  }
}

public class Dog extends Animal {
  public Dog(String name) {
    //Der Konstruktor der Superklasse muss aufgerufen werden
    super(name);
  }

  @Override
  public void sayHello() {
    System.out.println("Hallo mein Name ist " + getName() + " und ich bin eine Dog!");
    //Aufruf der Methode in der Superklasse.
    super.sayHello();
  }
}

Folgendes ist wichtig bei der Vererbung zu erwähnen. Die Subklasse muss den Konstruktor der Superklasse aufrufen, dies geschieht mittels super(...). Wenn es nur den Standardkonstruktor (keine Parameter) gibt, muss super() nicht aufgerufen werden.

Package

Klassen und Interfaces sind in Java immer in Packages unterteilt. Diese dienen zum Gruppieren nach verschiedenen Zugehörigkeiten. Die Package Definition befindet sich immer bei der Klasse oder dem Interface ganz oben. Die Dateien werden intern in Ordnern abgelegt.

package at.drlue.matura;

public class Matura {
  public void printNote() {
    System.out.println("Eins");
  }
}

Die Klasse Matura befindet sich in der Datei Matura.java, diese Datei befindet sich im Ordner at/drlue/matura/.

Sichtbarkeit

Die Sichtbarkeit einer Klasse, Methode oder eines Attributs kann über Schlüsselwörter verändert werden. Diese beschreiben von wo aus der Zugriff darauf erfolgen darf. Die Folgende Tabelle zeigt diese Schlüsselwörter und von wo aus der Zugriff erfolgen kann:

Sichtbarkeit[3]

Datei: at/drlue/matura/packageA/A.java

public class A {
  public String hi() {
    System.out.println("Hallo");
  }

  private String bye() {
    System.out.println("Bye");
  }

  protected String what() {
    System.out.println("Was geht?");
  }

  //Ohne Sichtbarkeitsmodifier ist es Default
  String howDoYouDo() {
    System.out.println("Wie geht es dir?");
  }
}

Datei: at/drlue/matura/packageB/B.java

public class B {
  private A a = new A();

  public String hiAccess() {
    a.hi();
  }

  public String byeAccess() {
    //Nicht möglich da Zugriff private
    //a.bye();
  }

  public String whatAccess() {
    //Zugriff möglich, da nicht im selben Package
    a.what();
  }

  public String howDoYouDoAccess() {
    //Zugriff nicht möglich, da nicht im selben Package
    a.howDoYouDo();
  }
}

Datei: at/drlue/matura/packageA/C.java

public class C {
  private A a = new A();

  public String hiAccess() {
    a.hi();
  }

  public String byeAccess() {
    //Nicht möglich da Zugriff private
    //a.bye();
  }

  public String whatAccess() {
    //Zugriff möglich, da selbes Package
    a.what();
  }

  public String howDoYouDoAccess() {
    //Zugriff möglich, da selbes Package
    a.howDoYouDo();
  }
}

Datei: at/drlue/matura/packageD/D.java

public class D extends A {
  private A a = new A();

  public String hiAccess() {
    a.hi();
  }

  public String byeAccess() {
    //Nicht möglich da Zugriff private
    //a.bye();
  }

  public String whatAccess() {
    //Zugriff möglich, da geerbt wird
    a.what();
  }

  public String howDoYouDoAccess() {
    //Zugriff nicht möglich, da nicht im selben Package obwohl geerbt wird
    a.howDoYouDo();
  }
}

Casten

Mittels Casting können untereinander kompatible Datentypen umgewandelt werden.

Casten von primitiven Datentypen

Primitive Datentypen enthalten, werden Sie einer Variable zugewiesen, wirklich den Wert den Sie repräsentieren. Ein casten führt wirklich zu einem neuen Wert (verändert aber nicht den alten). Alle primitiven Datentypen können untereinander umgewandelt werden, außer boolean.

long a = 10;
//long wird in int umgewandelt
int b = (int)a;
//einem long kann aber ohne Casting ein int zugewiesen werden
a = b;

Casten von Objekten

Objekte können nur in den Datentyp anderer kompatibler Klassen gecastet werden. Vereinfacht gesagt, es muss möglich sein, dass der Cast erfolgreich ist. Weiters ist hier zu erwähnen, dass keine Umwandlung der Daten erfolgt. Wird ein Objekt einer Variable zugewiesen, so ist dies nicht der Wert selbst, sondern nur eine Referenz darauf. Mit dem Cast wird nur das erwartete geändert, dass sich an der Stelle befindet, an die diese Referenz zeigt.

public class Tier {}

public class Auto {}
...
public static void main(String[] args) {
  Tier a = new Tier();
  //Zuweisung nicht möglich, da A niemals ein B sein kann
  //Auto b = (Auto)a;

  //Jede Klasse erbt von java.lang.Object kein Cast ist erforderlich da A ein Object ist
  Object obj = a;
  //Dieser Cast ist möglich, wir wissen zwar dass dies zu einer ClassCastException führt
  Auto b = (Auto) obj;
}

Exceptions

Exceptions oder Ausnahmen können von Methoden und auch von Konstruktoren geworfen werden. Eine Exception tritt auf, wenn eine Methoden außerhalb ihrer gewünschten Funktionalität operiert. Jede Exception ist ein java.lang.Throwable, d.h. Sie kann mittels des Schlüsselworts throw geworfen werden. Weiters unterscheiden wir zwei Arten von Exceptions.

Checked Exceptions

Dazu gehört jede Exception die von java.lang.Throwable erbt, aber keine java.lang.RuntimeException und kein java.lang.Error ist. Wenn Checked Exceptions geworfen werden, so muss dies in der Methode mittels throws ExceptionName deklariert werden. Zusätzlich muss die geworfene Exception auch immer von der Aufrufenden Methode behandelt, oder weitergeworfen, werden.

Unchecked Exceptions

Dazu gehören Alle Exceptions welche von java.lang.Error oder von java.lang.RuntimeException erben. Diese Exceptions müssen nicht in der Methoden Definition deklariert werden. Sie können abgefangen und behandelt werden, (müssen sie aber nicht), normalerweise sollten diese aber überhaupt nicht auftreten.

Beispiele für RuntimeExceptions
Klasse Code
java.lang.IndexOutOfBoundsException
int[] arr = new int[]{1,2,3,4};
//Index existiert nicht
System.out.println(arr[5]);
java.lang.NullPointerException
Animal a = null;
//Die Referenz ist null, beim Zugriff crashts
System.out.println(a.toString());
Beispiele für Errors
Klasse Code
java.lang.OutOfMemoryError
//Tritt auf wenn keine weiteren neuen Objekte mehr erstellt werden können
List<int[]> list = new LinkedList<>();
while(true) {
  list.add(new int[10000]);
}

Exceptions selbst definieren

Natürlich können auch eigene Exceptions erstellt werden. Sinnvoll ist dies, wenn die eigene Exception einen Mehrwert an Information liefert. Um eine eigene Exception zu erstellen wird einfach von Exception geerbt.

public class HttpStatusCodeException extends Exception {
  private int statusCode;
  private String url;

  public HttpStatusCodeException(int statusCode, String url) {
    //Text für die Exception wird erstellt
    super("Beim Aufruf von "+url+" ist ein Fehler mit dem Statuscode ["+statusCode+"] aufgetreten");
    this.statusCode = statusCode;
    this.url = url;
  }

  public int getStatusCode() {
    return statusCode;
  }

  public String getUrl() {
    return this.url;
  }

}
...
public static void main(String[] args) {
  try {
    executeRequest("https://drlue.at");
  } catch(HttpsStatusCodeException exc) {
    if(exc.getStatusCode() == 401) {
      login();
    }
  }
}

private static void executeRequest(String url) throws HttpStatusCodeException {
     Response resp = ...//network request
     if(!resp.isSuccessfull()) {
        throw new HttpStatusCodeException(resp.statusCode(), url);
     }
   }
}

Beispiele

Im folgenden Beispiel wird eine Methode erstellt, welche einen Dateinamen nimmt und die Länge der Datei zurückgibt. Existiert die Datei nicht, so wird eine java.lang.FileNotFoundException geworfen:

public static long getFileLength(String fileName) throws FileNotFoundException {
  File f = new File(fileName);
  if(!f.exists()) {
    throw new FileNotFoundException();
  }
  return f.length();
}

Die Methode können wir folgendermaßen verwenden, bei dieser Variante fangen wir die Exception ab:

public static void main(String[] args) {
  try {
    long length = getFileLength("wichtig.txt");
    System.out.println("Die Datei ist: "+length+"Bytes lang");
  } catch(FileNotFoundException exc) {
    System.out.println("Die Datei wurde nicht gefunden!");
  }
}

Eine weitere Variante ist, dass die Aufrufende Methode, die Exception weiter wirft.

public static void main(String[] args) throws FileNotFoundException {
  long length = getFileLength("wichtig.txt");
  System.out.println("Die Datei ist: "+length+"Bytes lang");
}

Es kann auch zuerst die Exception gefangen, und dann weitergeworfen werden. Eine weitere Variante ist, dass die Aufrufende Methode, die Exception weiter wirft.

public static void main(String[] args) throws FileNotFoundException {
  try {
    long length = getFileLength("wichtig.txt");
    System.out.println("Die Datei ist: "+length+"Bytes lang");
  } catch(FileNotFoundException exc) {
    System.out.println("Die Datei wurde nicht gefunden!");
    throw exc;
  }

Weitere wichtige Dinge

Hier sollen noch einige weitere Dinge abgeklärt werden.

Überladen von Methoden

Wir sprechen von überladen einer Methode, wenn mehrere Methoden in einer Klasse existieren die den selben Namen haben, sich aber die Übergabeparameter, entweder in ihrem Datentyp, oder der Anzahl unterscheiden. Ein Konstruktor kann ebenfalls überladen werden.
Im folgenden Beispiel wird die Methode add(...) überladen. Der Compiler entscheidet anhand des Datentyps der Parameter welche Methode verwendet werden soll, der Rückgabetyp spielt keine Rolle.

public class Calc {
  public int add(int a, int b) {
    return a + b;
  }

  public float add(float a, float b) {
    return a + b;
  }
}
...
public static void main(String[] args) {
  Calc c = new Calc();
  //Die add Methode mit den floats wird verwendet, weil die Parameter floats sind
  float a = c.add(3.0f, 2.0f);
  //Die add Methode mit den ints wird verwendet, weil die Parameter ints sind
  float a = c.add(3, 2); 
}

Polymorphismus

Polymorphismus oder Vielgestaltigkeit beschreibt den Sachverhalt, wenn ein Objekt des Typs A vorhanden ist, in Wirklichkeit ein B sein kann (natürlich nur wenn B von A erbt bzw. A implementiert, ansonsten kann das nicht sein). Die Vielgestaltigkeit bezieht sich somit auf das Aufrufen von Methoden. Wird eine Methode von A aufgerufen, so kann dies in Wirklichkeit die Methode in B aufrufen, wenn B diese überschreibt. Eine Methode ist Polymorph wenn diese in der Subklasse die selbe Methodensignatur aufweist wie in der Superklasse.

public class A {
  public void doSomething() {
    System.out.println("My name is A and I do something!");
  }
}

public class B extends A {
  @Override
  public void doSomething() {
    System.out.println("My name is B and I do something!");
  }
}
...
public static void main(String[] args) {
  reallyDoSomething(new B());
}

public static void reallyDoSomething(A a) {
  a.doSomething();
}

Obwohl in der Methode reallyDoSomething(A a) eine Instanz von A als Parameter erwartet wird, ist es in Wirklichkeit eine Instanz von B. Ein Aufruf von a.doSomething() führt nicht den Code in A sondern den Code in B aus, da doSomething() in B überschrieben wurde.

Beziehungen

Hier sollen noch die Beziehungen zwischen Klassen bzw. Objekten geklärt werden.

Is A

Wenn eine Klasse Cat eine Klasse Animal erweitert, d.h. von ihr erbt. Somit ist Cat ein Animal und die folgende Zuweisung ist möglich:

Cat cat = new Cat();
Animal animal = cat;

Umgekehrt ist das nicht zwingend so. Wenn ein Objekt vom Typ Animal vorhanden ist, so könnte es ein Objekt vom Typ Cat sein, muss es aber nicht. Um dies zu prüfen gibt es das Schlüsselwort instanceof und es kann ein Cast erfolgen. Die Umwandlung ist auch ohne Prüfung möglich, dies kann jedoch zu Abstürzen durch eine java.lang.ClassCastException führen.

public void doSomething(Animal animal) {
  if(animal instanceof Cat) {
    Cat cat = (Cat) animal;
    cat.miau();
  } else {
    System.out.println("Can't miau");
  }
}

Das selbe gilt genau gleich, wenn eine Klasse ein Interface implementiert.
Is A ist somit eine Erweiterung einer Klasse, oder eine Implementierung einer Schnittstelle.

Es handelt sich hierbei um eine starke Bindung, d.h. diese kann zur Laufzeit des Programmes nicht verändert werden.

Has A

Eine Has A Beziehung wird auch Komposition oder Zusammenstellung genannt. Komposition ist eine schwache Bindung. Sie kann während der Laufzeit des Programmes verändert werden. Folgendes Beispiel soll eine Has A Beziehung verdeutlichen:

public class Cat {
  private List<Spielzeug> spielzeuge = new ArrayList();

  public void addSpielzeug(Spielzeug spielzeug) {
    this.spielzeuge.add(spielzeug);
  }

  public void removeSpielzeug(Spielzeug spielzeug) {
    this.spielzeuge.remove(spielzeug);
  }
}

public class Spielzeug {

}
...
public static void main(String[] args) {
  Cat cat = new Cat();

  Spielzeug ball = new Spielzeug();

  cat.addSpielzeug(ball);
  
  cat.removeSpielzeug(ball);
}

Hier wird gezeigt, dass Objekten zur Laufzeit andere Objekte hinzugefügt und entfernt werden können.

Has A Beziehung ist eine schwache Bindung.

Multithreading

Threading oder Nebenläufigkeit bezeichnet den Vorgang in einem Programm das unterschiedliche Handlungsstränge aufweist. D.h. verschiedene Programmabläufe laufen parallel. Diese Parallelität kann wirklich parallel ablaufen, d.h. 2 oder mehr CPUs sind involviert, oder es kann pseudo parallel Ablaufen, zwischen den unterschiedlichen Abläufen wird sehr schnell hin und her gewechselt, aber alles läuft auf einer CPU. Je nach Implementierung der Java Virtual Machine läuft es wirklich parallel oder nur pseudo parallel (green Threads). Folgendes Beispiel soll einen parallelen Ablauf verdeutlichen:

public static void main(String[] args) {
  Thread a = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<10; i++) {
        System.out.println("Hallo von Thread A: "+i);
        try {
          Thread.sleep(100);
        } catch(InterruptedException exc) { }
      }
    }
  });

  Thread b = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<10; i++) {
        System.out.println("Hallo von Thread B: "+i);
        try {
          Thread.sleep(100);
        } catch(InterruptedException exc) { }
      }
    }
  });

  a.start();
  b.start();
}

Zuerst werden die Threads erstellt, diesen wird ein Objekt des Typs java.lang.Runnable mitgegeben. Alternativ kann auch eine Klasse erstellt werden, welche von java.lang.Thread erbt und die run() Methode überschreibt. Nach dem initialisieren, können die Thread Instanzen mittels start() gestartet werden, run() wird nun jeweils in einem anderen Thread aufgerufen, der Ablauf ist dadurch parallel, also gleichzeitig.

Thread safety

Wenn eine Klasse bzw. der Methoden ohne Einschränkung aus mehreren Threads verwendet werden kann, so spricht man von Thread safety, also eine oder eine Klasse ist Thread safe. Ist sie dies nicht, so kann es zu unerwünschtem Verhalten oder auch zu Exceptions führen.

Folgender Code verwendet die nicht Thread sichere Klasse java.util.ArrayList. Am Ende der Ausführung ist ersichtlich, dass nicht die gewünschte Anzahl an Elementen in die Liste Eingetragen wurde. Mit etwas glück, tritt sogar eine Exception auf, wenn die Liste im einen Thread gerade vergrößert werden muss, und der andere Thread ein Element einfügen will:

import java.util.ArrayList;
import java.util.List;

public class ThreadSafetyTest {
  public static void main(String[] args) throws InterruptedException {
    List<String> list = new ArrayList<>(); //Not thread safe

    Thread a = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };

    Thread b = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };

    a.start();
    b.start();

    a.join();
    b.join();

    System.out.println(list.size());
  }
}

Nachfolgender Code verwendet die Thread sichere Klasse java.util.Vector, das Ergebnis ist nun korrekt:

import java.util.List;
import java.util.Vector;

public class ThreadSafetyTest2 {
  public static void main(String[] args) throws InterruptedException {
    List<String> list = new Vector<>(); //Thread safe

    Thread a = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };

    Thread b = new Thread() {
      public void run() {
        for (int i = 0; i < 10000000; i++) {
          list.add("Hallo");
        }
      };
    };

    a.start();
    b.start();

    a.join();
    b.join();

    System.out.println(list.size());
  }
}

Synchronisierung

Verwendet ein Programm mehrere Threads so kann dies zu Problemen führen, wenn kritische Bereiche, welche nicht atomare Operationen enthalten gleichzeitig verwendet werden.

Atomare Operationen sind nicht Teilbar. Eine int Variable zu erhöhen ist Teilbar.
1) Nimm die Zahl und erhöhe sie um 1 2) Überschreibe den Speicherbereich der Zahl
private static int count = 0;

public static void main(String[] args) {
  Thread a = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<1000; i++) {
        count++;
      }
    }
  });

  Thread b = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<1000; i++) {
        count++;
      }
    }
  });

  a.start();
  b.start();
  
  //Warten bis die Threads beendet wurden
  try {
    a.join();
  } catch(InterruptedException exc) {}
  try {
    b.join();
  } catch(InterruptedException exc) {}
  System.out.println("Increments: "+(2000));
  System.out.println("Actual count: "+count);
  System.out.println("Difference: "+(2000 - count));
}

In diesem Beispiel ist ersichtlich, dass die Variable am Ende nicht 2000 ist, aufgrund dieser nicht atomaren Erhöhung der Zahl um 1.
Um nicht atomare Bereiche sicher zu machen, kann das Schlüsselwort synchronized verwendet werden. synchronized verwendet ein sogenanntes Object Lock um einen kritischen Bereich abzusichern. Beim Betreten wird dieses geholt, beim Verlassen zurückgegeben. Dieses Lock existiert bei jedem Objekt nur einmal. Kann es nicht geholt werden, so wird gewartet bis es verfügbar ist und erst dann wird der geschützte Bereich betreten.

Wie kann synchronized verwendet werden
Code Beschreibung
synchronized(object) {
  //kritischer Bereich
}
Das Lock wird von einem bestimmten Object geholt.
public synchronized void doSomething() {
  //kritischer Bereich
}
Das Lock wird von der Instanz geholt, zu der dieser Methodenaufruf gehört.
public static synchronized void doSomething() {
  //kritischer Bereich
}

                                                                                                                        

Synchronized kann auch bei statischen Methoden verwendet werden. Das Lock wird von der Klasse selbst geholt. Die geladene Klasse ist ebenfalls eine Instanz (von der eigenen Definition), diese existiert aber nur einmal.

Somit kann das oben genannte Beispiel gelöst werden:

private static int count = 0;

private static synchronized void increment() {
  count++;
}

public static void main(String[] args) {
  Thread a = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<1000; i++) {
        increment();
      }
    }
  });

  Thread b = new Thread(new Runnable() {
    public void run() {
      for(int i=0; i<1000; i++) {
        increment();
      }
    }
  });

  a.start();
  b.start();
  
  //Warten bis die Threads beendet wurden
  try {
    a.join();
  } catch(InterruptedException exc) {}
  try {
    b.join();
  } catch(InterruptedException exc) {}
  System.out.println("Increments: "+(2000));
  System.out.println("Actual count: "+count);
  System.out.println("Difference: "+(2000 - count));
}