Was ist ein Konstruktor
Ein Konstruktor ist eine spezielle Funktion zum Erstellen von Klasseninstanzen, die hauptsächlich zur Initialisierung von Eigenschaften dient. Außer dem Standardkonstruktor haben alle Konstruktoren denselben Namen wie die Klasse.
Einteilung der Dart-Konstruktoren:
- Generativer Konstruktor (Generative)
- Standardkonstruktor (Default)
- Benannter Konstruktor (Named)
- Konstantenkonstruktor (Const)
- Umleitender Konstruktor (Redirecting)
- Fabrikkonstruktor (Factory)
- Umleitender Fabrikkonstruktor
- Kompakte Konstruktorsyntax (Dart 3.13+)
- Hauptkonstruktor (Primary Constructors, minimale Felder + Konstruktor-Syntax)
1. Generativer Konstruktor Generative Constructor
Der grundlegendste Konstruktor, erstellt Instanzen und initialisiert Member-Variablen. Er unterstützt Initialisierungsparameter this.Variable zur Vereinfachung der Zuweisung.
class Point {
double x;
double y;
// Generativer Konstruktor, this.x übergibt Parameter direkt an Member-Variablen
Point(this.x, this.y); // Weist x und y direkt Werte zu
}
void main() {
final p = Point(10, 20);
print("(${p.x}, ${p.y})"); // (10, 20)
}
Code-Sprache: JavaScript (javascript)
2. Standardkonstruktor Default Constructor
Wenn eine Klasse manuell keinen Konstruktor definiert, stellt Dart automatisch einen parameterlosen, unbenannten generativen Konstruktor zur Verfügung. Das Verhalten entspricht anderen C-ähnlichen Sprachen wie C++, Java, C# usw.
class PointA {
double x = 0;
double y = 0;
// Impliziter Standardkonstruktor: PointA();
}
void main() {
final p = PointA(); // Ruft automatisch den Standardkonstruktor auf
print("(${p.x}, ${p.y})"); // (0.0, 0.0)
}
Code-Sprache: PHP (php)
Hinweis: Sobald Sie einen beliebigen Konstruktor manuell schreiben, verschwindet der Standardkonstruktor.
3. Benannter Konstruktor Named Constructor
Zweck: Mehrere Konstruktoren pro Klasse mit klarer Semantik definieren; Syntaxformat Klassenname.Konstruktorname()
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
// Hauptgenerativer Konstruktor
Point(this.x, this.y);
// Benannter Konstruktor: Ursprungspunkt
Point.origin() : x = xOrigin, y = yOrigin;
}
void main() {
final p1 = Point(5, 6);
final p2 = Point.origin(); // Aufruf des benannten Konstruktors
print(p1.x); //5
print("Ursprung: (${p2.x}, ${p2.y})"); // (0,0)
}
Code-Sprache: PHP (php)
Wichtige Regeln
- Unterklassen erben keine benannten Konstruktoren von der Oberklasse; ein gleichnamiger benannter Konstruktor muss bei Bedarf manuell implementiert werden;
- Benannte Konstruktoren unterstützen Initialisierungslisten zur Zuweisung von final-Variablen.
4. Konstantenkonstruktor Const Constructor
Dient zur Erstellung von Kompilierzeitkonstantenobjekten, Voraussetzungen:
- Alle Member-Variablen mit
finalmarkieren - Dem Konstruktor das Schlüsselwort
constvoranstellen. Bei der Instanziierung mitconstwird der Konstantencache wiederverwendet; ohne const wird ein reguläres neues Objekt erstellt.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0); // Statisch zur Klasse gehörend, gemeinsam genutztes Objekt für alle Instanzen
final double x, y;
// Konstantenkonstruktor initialisiert final deklarierte x und y
const ImmutablePoint(this.x, this.y);
}
void main() {
// Kompilierzeitkonstante, nutzt dasselbe Objekt erneut
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2); // Nur bei identischen Parametern wird dieselbe Instanz verwendet
print(p1 == p2); // true
// Reguläre Instanz, neues separates Objekt
final p3 = ImmutablePoint(1, 2);
print(p1 == p3); // false
}Code-Sprache: PHP (php)
5. Umleitender Konstruktor Redirecting Constructor
Ein Konstruktor, der mit der Syntax : this(Parameter) die Ausführung an einen anderen Konstruktor derselben Klasse weiterleitet. Der Funktionskörper muss leer sein.
class Point {
double x, y;
// Hauptkonstruktor
Point(this.x, this.y);
// Umleitender Konstruktor: nur x übergeben, y fest auf 0 setzen, Weiterleitung an Hauptkonstruktor
Point.alongX(double x) : this(x, 0); // Ruft benannten Konstruktor auf, übergibt x an Hauptkonstruktor und fixiert y=0
}
void main() {
final p = Point.alongX(9);
print("x=${p.x}, y=${p.y}"); // x=9, y=0
}
Code-Sprache: JavaScript (javascript)
6. Fabrikkonstruktor Factory Constructor
Mit dem Schlüsselwort factory markiert, Einsatzszenarien:
- Nicht immer neue Objekte erstellen (Cache-Wiederverwendung, Rückgabe von Unterklasseninstanzen)
- Komplexe Logik vor Objekterstellung (JSON-Parsing, Parameterprüfung). Einschränkung: kein Zugriff auf
this
Singleton-Cache Logger Beispiel
class Logger {
final String name;
bool mute = false;
// Privater Cache, nur innerhalb der Bibliothek sichtbar
static final Map<String, Logger> _cache = {};
// Fabrikkonstruktor: Zuerst aus Cache abrufen
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// Fabrikkonstruktor: Erstellen aus JSON-Parsing
factory Logger.fromJson(Map<String, dynamic> json) {
return Logger(json["name"].toString());
}
// Privater interner generativer Konstruktor
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
final log1 = Logger("UI");
final log2 = Logger("UI");
print(log1 == log2); // true, dasselbe Cache-Objekt
final jsonLog = Logger.fromJson({"name": "Net"});
jsonLog.log("request success");
}
Code-Sprache: JavaScript (javascript)
7. Umleitender Fabrikkonstruktor Redirecting Factory
Syntax factory Name() = KonstruktorAndereKlasse;, geeignet für abstrakte Klassen, die die Instanzerstellung delegieren und wiederholte Parameterdefinitionen vermeiden.
abstract class Listenable {}
class _MergingListenable implements Listenable {
List<_MergingListenable> list;
_MergingListenable(this.list);
}
// Umleitende Fabrik, ruft Konstruktor der internen privaten Klasse auf
factory Listenable.merge(List<Listenable> list) = _MergingListenable;
Code-Sprache: PHP (php)
8. Konstruktor-Tear-offs
Konstruktoren direkt als Funktionsargument übergeben, ohne () zu schreiben. Ersetzt überflüssige Lambda-Anonyme Funktionen und bietet bessere Performance.
Empfohlene Schreibweise
void main() {
final charCodes = [65, 66, 67];
// Benannter Konstruktor String.fromCharCode
final strs = charCodes.map(String.fromCharCode);
print(strs); // (A, B, C)
// Unbenannter Konstruktor-Tear-off mit .new
final buffers = charCodes.map(StringBuffer.new);
}
Code-Sprache: PHP (php)
Nicht empfohlen: Überflüssiges Lambda
// Überflüssige Umhüllung, vermeiden
charCodes.map((code) => String.fromCharCode(code));
Code-Sprache: JavaScript (javascript)
9. Kompakte Konstruktorsyntax (Dart 3.13+) Concise Constructor
Innerhalb der Klasse kann der Klassenname weggelassen werden, direkt new / factory zur Definition von Konstruktoren verwenden, ohne Klassenname.xxx zu schreiben:
| Traditionelle Schreibweise | Kurzschreibweise |
|---|---|
Point(this.x,this.y) | new(this.x,this.y) |
Point.origin():x=0,y=0 | new origin():x=0,y=0 |
factory Point.clone() | factory clone() |
class Point {
double x, y;
// Kompakter unbenannter generativer Konstruktor
new(this.x, this.y);
// Kompakter benannter generativer Konstruktor
new origin() : x = 0, y = 0;
// Kompakter Fabrikkonstruktor
factory clone(Point other) => new(other.x, other.y);
}
void main() {
final p = new(3, 4);
final origin = new origin();
final copy = p.clone(p);
}
Code-Sprache: PHP (php)
10. Drei Methoden zur Initialisierung von Instanzvariablen
1: Direkte Zuweisung bei Deklaration
class PointA {
double x = 1.0;
double y = 2.0;
}
Code-Sprache: JavaScript (javascript)
2: Initialisierungsparameter
this.Variable
Unterstützt optionale Positionsparameter, benannte Parameter und nullable Variablen
class PointB {
final double x;
final double y;
// Optionale Positionsparameter
PointB.opt([this.x = 0, this.y = 0]);
// Benannte Parameter mit Standardwert
PointB.named({this.x = 5, this.y = 5});
}
Code-Sprache: JavaScript (javascript)
3: Initialisierungsliste Initializer List
Zuweisungen nach dem Doppelpunkt :, wird vor dem Konstruktorkörper ausgeführt, darf nicht auf this zugreifen, unterstützt assert zur Parameterprüfung.
class Point {
final double x;
final double y;
Point.fromJson(Map<String, double> json)
: x = json["x"]!,
y = json["y"]! {
print("Konstruktorkörper ausgeführt, x=$x");
}
// Mit Assert-Prüfung
Point.withAssert(this.x, this.y) : assert(x >= 0);
}
Code-Sprache: JavaScript (javascript)
11. Direkte Initialisierungsparameter für private Felder (Dart3.12+)
Bei privaten Variablen mit Unterstrichprefix schreibt man Konstruktorparameter als this._Feld. Bei externem Aufruf wird der öffentliche Name ohne Unterstrich verwendet.
class Point {
final double _x;
final double _y;
// Intern _x, externer Aufruf schreibt x:10
Point({required this._x, this._y = 0});
}
void main() {
final p = Point(x: 10); // Kein _x nötig, direkt x
print(p._x); // 10
}
Code-Sprache: PHP (php)
In der Initialisierungsliste den ursprünglichen Namen der privaten Variable verwenden:
class Point {
final double _x;
Point({required this._x}) : assert(_x > 0);
}
Code-Sprache: JavaScript (javascript)
12. Oberklassenkonstruktoren und Vererbungsregeln
- Unterklassen erben keine Konstruktoren der Oberklasse;
- Ausführungsreihenfolge des Konstruktors: Initialisierungsliste → Oberklassenkonstruktor → Unterklassen-Konstruktorkörper;
- Wenn die Oberklasse keinen parameterlosen Standardkonstruktor besitzt, muss die Unterklasse manuell mit
super()den Oberklassenkonstruktor angeben.
Einfaches super-Aufrufbeispiel
Wie Java nutzt man super zur Referenz der Basisklasse, in C# wird base verwendet.
class Person {
final String name;
Person(this.name);
Person.fromMap(Map map) : name = map["name"];
}
class Employee extends Person {
int id;
// Aufruf des benannten Oberklassenkonstruktors
Employee(Map data) : super.fromMap(data), id = data["id"];
}
Code-Sprache: JavaScript (javascript)
Hinweis: Innerhalb von super-Parameterausdrücken darf
thisnicht verwendet werden.
Super-Parameter (Dart2.17+, vereinfacht die Parameterübergabe an die Oberklasse)
Mit super.Variable Parameter direkt an den Oberklassenkonstruktor weiterreichen, ohne manuell super(x,y) schreiben zu müssen
class Vector2d {
final double x, y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// super.x super.y werden automatisch an den Oberklassenkonstruktor übergeben
Vector3d(super.x, super.y, this.z);
}
// Benannter Oberklassenkonstruktor + benannte Super-Parameter
class Vector3dYZ extends Vector2d {
final double z;
Vector3dYZ({required super.y, required this.z}) : super.named(x: 0);
}
Code-Sprache: JavaScript (javascript)