Was sind Klassen und Objekte
Eine Klasse ist eine Kategorie, eine Einteilung. Wir abstrahieren Dinge aus unserer Umgebung und fassen sie zu einem einheitlichen Typ zusammen. Beispielsweise abstrahieren wir alle Menschen auf der Erde zu einer Klasse „Mensch“. Einzelne konkrete Personen wie Bob oder Tom sind dann Objekte.
Eine Klasse funktioniert wie ein „Bauplan“ oder eine „Vorlage“, die Struktur und Verhalten aller zugehörigen Objekte definiert.
Nehmen wir wieder die Klasse Mensch als Beispiel: Diese Vorlage legt fest, was ein Mensch besitzt und was er tun kann. Er hat einen Namen, Arme, Beine und andere Körperorgane; er kann sprechen und nachdenken. Angaben wie Name oder Alter zählen zu den Eigenschaften einer Klasse, Handlungen wie Sprechen oder Denken zu ihrem Verhalten. Kurz gesagt extrahiert eine Klasse gemeinsame Merkmale aus realen Objekten. Mit dieser Vorlage lassen sich beliebig viele einzelne Objekte wie Jack oder Jim erstellen.
Die zuvor genannten Klasseneigenschaften (Name, Alter) und das Klassenverhalten (Sprechen, Denken) werden jeweils durch Variablen und Funktionen abgebildet.
Sie legt fest, welche Eigenschaften (Variablen) und Methoden (Funktionen) ein Objekt haben muss.
Eine Klasse lässt sich mit einer Backform vergleichen: Sie ist kein fertiges Produkt. Mit einer einzigen Form lassen sich viele einzelne Brote herstellen, genau wie mit einer Klasse viele Objekte.
Zu Beginn der Programmiergeschichte gab es noch kein Konzept der Klasse. Die Sprache C ist ein typisches Beispiel: Sie arbeitet nur mit Funktionen, Variablen und verschiedenen Anweisungen – man spricht hier von prozeduraler Programmierung. Mit wachsender Komplexität von Software zeigten sich gravierende Nachteile dieses Ansatzes: Viel doppelter Code, unübersichtliche Strukturen und fehlende Hierarchien. Später entwickelte sich das objektorientierte Paradigma: Man abstrahiert Programmlogik in einzelne Objekte, analog zur echten Welt. Man kann das mit einem Unternehmen vergleichen: Am Anfang erledigt der Chef alle Aufgaben selbst. Sobald er Mitarbeiter einstellt, delegiert er Buchhaltung an die Finanzabteilung und Personalbeschaffung an die Personalabteilung. Durch die Aufteilung der Aufgaben wird der gesamte Ablauf deutlich übersichtlicher.
Ein Objekt ist eine Instanz einer Klasse.
Wenn Sie das Schlüsselwort new oder einen Konstruktor aufrufen, erzeugt die Klasse ein neues Objekt.
Ein Objekt ist eine zur Laufzeit vorhandene Instanz, die Daten speichern und Methoden aufrufen kann.
Die Beziehung zwischen Klassen und Objekten
- Die Klasse ist der Bauplan, das Objekt das daraus gebaute fertige Haus.
- Aus einer einzigen Klasse lassen sich mehrere Objekte erzeugen, jedes mit eigenen unabhängigen Daten.
- Alle Objekte aus derselben Klasse teilen die darin definierten Verhaltensweisen (Methoden).

Wechseln wir nun zur Sprache Dart
Folgende Themen werden wir behandeln
Dart ist eine vollständig objektorientierte Sprache. Jeder Wert ist eine Instanz einer Klasse. Außer Null erben alle Klassen von der Basisklasse Object.
Dart realisiert Vererbung durch die Kombination von Klassen und Mixins
Einfachvererbung: Jede Klasse kann nur eine einzige Elternklasse haben, aber Mixins ermöglichen die Wiederverwendung mehrerer Logikblöcke aus verschiedenen Klassen
Erweiterungsmethoden: Man kann einer Klasse neue Funktionen hinzufügen, ohne deren Quellcode zu ändern oder eine Unterklasse zu erstellen
Klassenmodifikatoren: Steuern, ob andere Bibliotheken diese Klasse erben oder implementieren dürfen
Jetzt beginnen wir mit dem Lernen von Klassen in Dart
Klassenmitglieder
Zu den Klassenmitgliedern zählen Methoden und Variablen – sie sind die Bestandteile, aus denen eine Klasse besteht.
Mit dem Operator . greift man auf Instanzmitglieder zu; der Null-Sicherheitsoperator ?. verhindert Nullpointer-Ausnahmen
Hier ist ein vollständiges Beispiel, das das Definieren einer Klasse, das Erstellen von Objekten aus der Klasse und das Aufrufen von Mitgliedern über den Objektnamen zeigt
// Klasse definieren, entspricht dem Erstellen einer Form
class Point {
double x, y;
Point(this.x, this.y);
// Instanzmethode: Berechnet das Quadrat des Abstands zwischen zwei Punkten
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
// Objekt p aus der Klasse Point erstellen, um Operationen durchzuführen
var p = Point(2, 2);
// Auslesen einer Instanzvariablen (impliziter Getter)
print(p.y); //2.0
// Aufruf einer Instanzmethode
double dist = p.distanceTo(Point(4, 4));
print(dist); // 8.0
// Null-sicherer Zugriff mit ?.
Point? nullablePoint;
var a = nullablePoint?.y; // Ist das Objekt null, erhält a direkt null ohne Ausnahme
print(a); // null
}Code-Sprache: JavaScript (javascript)

Konstruktoren (Constructors)
Standardkonstruktoren
Dart unterscheidet sich von anderen C-ähnlichen Sprachen durch unterstützte benannte Konstruktoren. Bei den meisten C-abgeleiteten Sprachen muss der Konstruktor den gleichen Namen wie die Klasse tragen, Dart erlaubt dagegen Konstruktoren mit von dem Klassennamen abweichenden Bezeichnern.
Syntax: Klassenname() / Klassenname.Bezeichner();
Das Schlüsselwort new ist optional (verfügbar ab Dart 2)
class Point {
double x, y; // Zwei Variablen als Klassenmitglieder zur Speicherung von Klasseneigenschaften
// Standardkonstruktor zur Initialisierung der Variablen x und y
Point(this.x, this.y);
// Benannter Konstruktor Point.fromJson: Initialisiert x und y mit JSON-Daten
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']!;
}
void main() {
var p1 = Point(2, 2);// Aufruf des Standardkonstruktors, übergibt 2 und 2, initialisiert p1 mit x=2, y=2
var p2 = Point.fromJson({'x': 1, 'y': 2}); // Übergibt JSON an den benannten Konstruktor fromJson
// new kann weggelassen werden, das Verhalten ist identisch
var p3 = new Point(3, 3); // Erstellt Objekt über den Standardkonstruktor
print("p1:(${p1.x},${p1.y}), p2:(${p2.x},${p2.y}), p3:(${p3.x},${p3.y})");
// Ausgabe: p1:(2.0,2.0), p2:(1.0,2.0), p3:(3.0,3.0)
}Code-Sprache: JavaScript (javascript)
Konstantenkonstruktoren mit const
Stellen Sie einem Konstruktor das Schlüsselwort const voran, um Kompilierzeit-Konstantenobjekte zu erzeugen. Konstanten mit identischen Parametern nutzen dieselbe Instanz wieder.
class ImmutablePoint {
final double x, y;
// Regel für Konstantenkonstruktoren: Alle Mitglieder müssen mit final markiert sein
const ImmutablePoint(this.x, this.y);
}
void main() {
// Erstellen von Konstanteninstanzen
var a = const ImmutablePoint(1, 1); // const ist auch bei der Instanzerstellung erforderlich
var b = const ImmutablePoint(1, 1);
print(identical(a, b)); // true, verweisen auf dasselbe Objekt
var m = const ImmutablePoint(1, 1);
var n = const ImmutablePoint(2, 1);
print(identical(m, n)); // false, abweichender x-Wert ergibt separate Objekte
// Ohne const handelt es sich um normale Objekte ohne gemeinsame Instanz
var c = ImmutablePoint(1, 1);
print(identical(a, c)); //false
// Innerhalb eines const-Kontexts kann das innere const weggelassen werden
const pointMap = {
'p1': [ImmutablePoint(0, 0)],
'p2': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)]
};
print(pointMap); //{p1: [Instance of 'ImmutablePoint'], p2: [Instance of 'ImmutablePoint', Instance of 'ImmutablePoint']}
print(identical(p1, p2)); // false
print(identical(p2, p3)); // false
print(identical(p1, p3)); // false
}Code-Sprache: PHP (php)
Ein Konstantenkonstruktor nutzt nur dann dieselbe Instanz wieder, wenn alle übergebenen Parameter vollständig übereinstimmen. Schon ein abweichender Parameter erzeugt zwei unabhängige Objekte.
Laufzeittyp eines Objekts abfragen mit runtimeType
Mit Objekt.runtimeType erhalten Sie den Typ zur Laufzeit. Bevorzugen Sie aber den Typ-Prüfoperator is statt Vergleiche mit runtimeType
class Point {
double x, y;
Point(this.x, this.y);
// Instanzmethode: Berechnet das Quadrat des Abstands zwischen zwei Punkten
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
var p = Point(2, 3);
print("Typ von p: ${p.runtimeType}"); // Point
// Empfohlene stabile Prüfweise
if (p is Point) {
print("p ist eine Instanz von Point");
}
// Für Produktcode nicht empfohlen
if (p.runtimeType == Point) {
print("p ist eine Instanz von Point ");
}
}Code-Sprache: JavaScript (javascript)
Instanzvariablen Instance Variables
- Nicht initialisierte nullable Typen haben standardmäßig den Wert
null; nicht-nullbare Typen müssen zwingend initialisiert werden - Alle Instanzvariablen erhalten automatisch einen impliziten Getter; nicht-final oder uninitialisierte late-final-Variablen bekommen zusätzlich einen automatischen Setter
- Normale Initialisierungsausdrücke von Instanzvariablen dürfen this nicht aufrufen; bei late-Variablen ist der Zugriff auf this in der Initialisierung erlaubt
- Final-Instanzvariablen lassen sich nur einmal zuweisen: Bei der Deklaration, über Konstruktorparameter oder in der Konstruktor-Initialisierungsliste
Implizite Getter und Setter
class Point {
double? x; // Initialwert null, automatischer Getter + Setter
double? y;
double z = 0; // Initialwert 0
}
void main() {
var point = Point();
point.x = 4; // Aufruf des impliziten Setters
assert(point.x == 4); // Aufruf des impliziten Getters
assert(point.y == null);
print(point.z); // 0
}
Code-Sprache: JavaScript (javascript)
Zugriffsbeschränkung von this in Initialisierungsausdrücken
double globalX = 1.5;
class Point {
// Erlaubt: Zugriff auf externe globale Variable ohne this
double? x = globalX;
// Kompilierfehler: Standardinitialisierung darf this nicht nutzen
// double? y = this.x;
// Erlaubt: late-Variablen dürfen this bei der Initialisierung referenzieren
late double? z = this.x;
// Erlaubt: Der Syntax-Sugar this.x bei Konstruktorparametern zählt nicht als Initialisierungsausdruck
Point(this.x, this.y);
double? y;
}
void main() {
var p = Point(null, 5);
print(p.z); // null
}
Code-Sprache: JavaScript (javascript)
Drei Initialisierungswege für final-Instanzvariablen
class ProfileMark {
// Weg 1: Direkte Initialisierung bei der Deklaration
final DateTime start = DateTime.now();
final String name;
// Weg 2: Zuweisung über Konstruktorparameter
ProfileMark(this.name);
// Weg 3: Zuweisung in der Konstruktor-Initialisierungsliste; der benannte Konstruktor unnamed setzt name standardmäßig auf leeren String
ProfileMark.unnamed() : name = '';
}
void main() {
var m1 = ProfileMark("user1");
var m2 = ProfileMark.unnamed();
print(m1.name);
print(m2.name);
}
Code-Sprache: PHP (php)
Implizite Schnittstellen Implicit interfaces
Jede Dart-Klasse besitzt eine implizite Schnittstelle, die alle öffentlichen Instanzmitglieder der Klasse umfasst.
implements: Implementiert eine Schnittstelle, alle Methoden der Schnittstelle müssen überschrieben werdenextends: Vererbung, wiederverwendet die Implementierung der Elternklasse- Private Variablen mit Präfix
_xxxwerden nicht an die Schnittstelle exponiert
1 Implementieren einer einzelnen Schnittstelle
class Person {
final String _name;
Person(this._name);
// Öffentliche Schnittstellenmethode
String greet(String who) => "Hello $who, I'm $_name";
}
// Implementiert die Person-Schnittstelle, alle Schnittstellenmitglieder müssen überschrieben werden
class Impostor implements Person {
String get _name => "";
@override
String greet(String who) => "Hi $who, guess who?";
}
String greetBob(Person p) => p.greet("Bob");
void main() {
print(greetBob(Person("Kathy")));
print(greetBob(Impostor()));
}
Code-Sprache: PHP (php)
Wenn eine Unterklasse Methoden der Elternschnittstelle überschreibt, markieren Sie dies mit der Annotation @override – ähnlich wie bei Java. Zum Implementieren einer Schnittstelle nutzen Sie das Schlüsselwort implements.

2 Implementieren mehrerer Schnittstellen
// Abstrakte Klasse
abstract class Comparable {
int compareTo(Object other);
}
// Abstrakte Klasse
abstract class Location {
double get x;
double get y;
}
// Implementiert zwei Schnittstellen gleichzeitig
class Point implements Comparable, Location {
@override
double x, y;
Point(this.x, this.y);
@override
int compareTo(Object other) {
if (other is Point) {
return (x + y).compareTo(other.x + other.y);
}
return -1;
}
}
void main() {
var p = Point(2, 3);
print(p.x);
print(p.compareTo(Point(1, 1)));
}
Code-Sprache: PHP (php)
@override
double x, y;
Diese Annotation bedeutet: Diese beiden Eigenschaften überschreiben die abstrakten Getter, die in der übergeordneten Schnittstelle Location definiert sind.
Statische Variablen & statische Methoden static
1. Statische Variablen static (Klassenvariablen, global eindeutig)
- Sie gehören zur Klasse selbst, nicht zu einzelnen Instanzen; verzögerte Initialisierung: Sie werden erst bei dem ersten Zugriff erstellt
- Konstante statische Variablen sollten nach lowerCamelCase benannt werden
class Queue {
static const initialCapacity = 16; // Statische Konstante
static int count = 0; // Statische veränderliche Variable
Queue() {
count++;
}
}
void main() {
assert(Queue.initialCapacity == 16); // Wird bei Zugriff initialisiert, Standardwert 16
Queue(); // Erhöht count um 1
Queue();
print(Queue.count); // 2
}
Code-Sprache: JavaScript (javascript)
2. Statische Methoden static (Klassenmethoden)
- Sie besitzen keine Referenz
this, können also keine Instanzmitglieder aufrufen, nur statische Variablen - Aufruf direkt über die Syntax
Klassenname.Methode() - Sie können als Kompilierzeitkonstanten an Konstantenkonstruktoren übergeben werden
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
// Statische Methode: Berechnet den direkten Abstand zwischen zwei Punkten
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var dist = Point.distanceBetween(a, b);
print(dist); // ca. 2,828
}Code-Sprache: JavaScript (javascript)

Statische Methoden gehören zur Klasse, daher müssen sie über den Klassennamen aufgerufen werden, wobei zwei Point-Instanzen als Parameter übergeben werden.