1. Objekt erstellen
Jetzt sind wir beim Erstellen von Objekten angekommen. Du bist damit bestimmt schon mal in Berührung gekommen, aber jetzt schauen wir uns das Ganze genauer an. Eigentlich ist das Erstellen von Objekten super easy.
Um ein Objekt zu erstellen, benutzt du den Operator new. Normalerweise erzeugst du eine neue Instanz (also ein Objekt) einer Klasse und speicherst sie direkt in einer Variablen vom gleichen Typ.
Klasse name = new Klasse(parameter);
Dabei ist Klasse der Typ des Objekts, name der Name der Variable (oft klein geschrieben, z.B. cat), und rechts vom = steht die Erstellung eines neuen Objekts dieser Klasse.
Beispiele:
| Code | Hinweis |
|---|---|
|
Erstellen eines Objekts vom Typ object |
|
Erstellen eines Objekts vom Typ Cat |
|
Erstellen eines StreamReader-Objekts mit Parameter |
Sehr oft nennen Programmierer Variablen genauso wie die Klassen, nur mit kleinem Anfangsbuchstaben. Für Anfänger kann so ein Code verwirrend sein:
| Code |
|---|
|
|
|
Eigentlich ist an diesem Code nichts Schlimmes — das ist ganz normaler Code, in dem eine Variable erstellt und direkt mit einem Objekt ihres Typs initialisiert wird.
Links steht die Deklaration der Variable, rechts die Erstellung eines neuen Objekts im Speicher mit new. Das war's!
2. Konstruktor
Du hast bestimmt schon oft gesehen, dass beim Erstellen eines Objekts irgendwelche Parameter übergeben werden. Manchmal werden Parameter übergeben, manchmal nicht. Wie funktioniert das eigentlich mit diesen Parametern?
Auch das ist easy: Jede Klasse hat eine spezielle Methode (oder mehrere), die für die Verarbeitung der Parameter beim Erstellen eines Objekts zuständig ist. Diese Methoden nennt man Konstruktoren. Eine einzelne Methode ist dann ein Konstruktor.
Einen Konstruktor von einer normalen Methode zu unterscheiden ist nicht schwer. Ein Konstruktor hat zwei Besonderheiten:
- Der Name des Konstruktors ist identisch mit dem Klassennamen (und beginnt mit einem Großbuchstaben)
- Ein Konstruktor hat keinen Rückgabewert (nicht mal void wird geschrieben).
So sieht das Ganze meistens aus:
modifikatoren Klasse(parameter)
{
konstruktor-code
}
Beispiel für die Deklaration eines Konstruktors:
public class Point
{
public int X;
public int Y;
public Point(int x, int y) // Konstruktor
{
X = x;
Y = y;
}
}
Verwendung:
Point p = new Point(5, 10); // Aufruf des Konstruktors
Beim Erstellen eines Objekts mit new Point(5, 10) wird der Konstruktor mit zwei Parametern aufgerufen, die die Felder X und Y initialisieren.
Manchmal haben die Parameter des Konstruktors die gleichen Namen wie die Felder — das ist zur Bequemlichkeit. So ein Namenskonflikt wird mit dem Schlüsselwort this gelöst:
public Point(int x, int y)
{
this.x = x; // this.x — Feld des Objekts, x — Parameter des Konstruktors
this.y = y;
}
3. Konstruktor aufrufen
Wenn du new Klasse(parameter) schreibst, macht C# folgendes:
- erstellt ein neues Objekt im Speicher,
- ruft den passenden Konstruktor auf und übergibt deine Parameter.
Beispiel mit der Klasse Cat:
public class Cat
{
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
}
Verwendung:
Cat cat = new Cat("Vaska", 2); // Geht: Konstruktor mit zwei Parametern wird aufgerufen
Cat cat2 = new Cat("Vaska"); // Geht nicht: Es gibt keinen solchen Konstruktor — Compilerfehler
Cat cat3 = new Cat(); // Geht nicht: Kein Konstruktor ohne Parameter — Compilerfehler
Wenn die Klasse nur einen Konstruktor mit Parametern hat, musst du beim Erstellen des Objekts Werte für diese Parameter angeben.
4. Mehrere Konstruktoren
Wenn du willst, kannst du in einer Klasse mehrere Konstruktoren haben. Es gibt keine Begrenzung für die Anzahl der Konstruktoren oder deren Parameter. Beim Erstellen eines Objekts sucht sich der Compiler automatisch den passenden Konstruktor anhand der Parameter aus.
Beispiel:
public class Cat
{
public const int UNBEKANNT = -1;
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
public Cat(string name)
{
Name = name;
Age = UNBEKANNT; // "Standardwert" für unbekanntes Alter
}
}
Verwendung:
Cat cat1 = new Cat("Vaska", 2); // Nutzt den ersten Konstruktor
Cat cat2 = new Cat("Murka"); // Nutzt den zweiten Konstruktor
Cat cat3 = new Cat(); // Fehler! Kein Konstruktor ohne Parameter
Wir wollten berücksichtigen, dass das Alter der Katze vielleicht unbekannt ist. Dafür haben wir eine spezielle Konstante UNBEKANNT und einen Konstruktor, der nur einen Parameter — den Namen der Katze — nimmt.
Achte darauf, dass wir trotzdem beide Klassenvariablen in beiden Konstruktoren initialisieren. Fehlende/unbekannte Parameter ersetzen wir durch die Konstante UNBEKANNT.
5. Standardkonstruktor
Wenn deine Klasse keinen eigenen Konstruktor hat, fügt der Compiler automatisch einen leeren Konstruktor ohne Parameter hinzu:
public KlassenName()
{
}
Aber wenn in der Klasse schon mindestens ein eigener Konstruktor deklariert ist, wird der leere Konstruktor nicht mehr automatisch hinzugefügt.
Beispiel 1:
public class Cat
{
public string Name;
public int Age;
}
// Geht:
Cat cat = new Cat(); // Der Standardkonstruktor (ohne Parameter) wird aufgerufen
Beispiel 2:
public class Cat
{
public string Name;
public int Age;
public Cat(string name) { Name = name; }
}
// Geht nicht:
Cat cat = new Cat(); // Fehler: Es gibt keinen Konstruktor ohne Parameter mehr!
6. Initialisierung von Variablen
In C# kannst du Klassenvariablen entweder direkt bei der Deklaration oder im Konstruktor initialisieren.
Beispiel:
public class Cat
{
public string Name;
public int Age = -1; // Startwert
public Cat(string name, int age)
{
Name = name;
Age = age; // Überschreibt den Startwert
}
public Cat()
{
Name = "Namenlos";
// Age bleibt -1 (Startwert)
}
}
Erklärung:
- Beim Erstellen mit new Cat("Vaska", 2) ist die Variable Age zuerst -1, aber dann weist der Konstruktor ihr 2 zu.
- Beim Erstellen mit new Cat() bleibt Age bei -1.
7. Reihenfolge der Initialisierung von Variablen
Die Daten eines neuen Objekts werden in folgender Reihenfolge initialisiert:
- Felder der Klasse bekommen zuerst Standardwerte (0 für int, null für Referenztypen usw.).
- Dann werden die Initialisierer ausgeführt, die du bei der Deklaration der Felder angegeben hast, und zwar in der Reihenfolge, wie sie im Code stehen.
- Und erst danach wird der Code des Konstruktors ausgeführt.
Variablen werden vor dem Konstruktor und in der Reihenfolge der Deklaration initialisiert. Deshalb solltest du auf Abhängigkeiten zwischen Feldern achten.
Falsches Beispiel
Nichtstatische Felder darfst du nicht mit nichtstatischen Variablen initialisieren:
public class Solution
{
public int a = 1;
public int b = a; // a darf hier nicht verwendet werden
public int c = a + b; // a und b dürfen hier nicht verwendet werden
}
// So ein Code führt zu einem Compilerfehler!
Richtiges Beispiel
Bei statischen Variablen funktioniert alles:
public class Solution
{
public static int a = 1; // Wir setzen explizit a = 1
public static int b = a + 2; // b = 1 + 2 ⇒ 3
public static int c = a + b + 3; // c = 1 + 3 + 3 ⇒ 7
public Solution()
{
Console.WriteLine($"a = {a}, b = {b}, c = {c}");
// Gibt aus: a = 1, b = 3, c = 7 — genau wie erwartet
}
}
Richtiges Beispiel 2
Für statische Felder kannst du sogar sowas machen:
public class Solution
{
public static int a = b + c + 1; // b und c sind noch 0
public static int b = a + c + 2; // a == 1, c ist noch 0
public static int c = a + b + 3; // a == 1, b == 3
}
GO TO FULL VERSION