Die @override-Annotation
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 39 von 110.
Die @override-Annotation ist eine Best-Practice-Markierung, die Dart (und anderen Entwicklern) mitteilt, dass Sie absichtlich eine Methode einer Elternklasse ersetzen. Obwohl das Überschreiben von Methoden auch ohne sie funktioniert, bietet die Verwendung von @override ein wichtiges Sicherheitsnetz.
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}Die Annotation bietet zwei wesentliche Vorteile. Erstens dokumentiert sie Ihre Absicht klar – jeder, der den Code liest, weiß sofort, dass diese Methode in der Elternklasse existiert. Zweitens warnt Sie der Analyzer von Dart, wenn die Elternmethode tatsächlich nicht existiert, wodurch Tippfehler und Refactoring-Fehler frühzeitig erkannt werden.
Überlegen Sie, was passiert, wenn Sie den Methodennamen ohne @override falsch schreiben:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // Tippfehler! Keine Warnung ohne @override
print('$name meows');
}
}Ohne die Annotation nimmt Dart an, dass Sie eine neue Methode namens speek() erstellen. Mit @override würde der Analyzer sofort melden, dass eine solche Methode in der Elternklasse nicht existiert. Diese einfache Annotation verhindert subtile Fehler, die später schwer aufzuspüren sein können.
Aufgabe
EinfachLassen Sie uns ein Mediaplayer-System bauen, das die Bedeutung der @override-Annotation bei der Anpassung von geerbtem Verhalten demonstriert. Sie werden verschiedene Medientypen erstellen, die jeweils Inhalte auf ihre eigene Weise abspielen.
Sie werden Ihren Code in zwei Dateien organisieren:
media.dart: Definieren Sie hier Ihre Medienhierarchie:- Eine
Media-Klasse mit einerString title-Eigenschaft, einem Konstruktor, der den Titel entgegennimmt, und einer Methodeplay(), diePlaying: [title]ausgibt. - Eine
Song-Klasse, dieMediaerweitert und eineString artist-Eigenschaft hinzufügt. Verwenden Sie die@override-Annotation und überschreiben Sieplay(), umPlaying song: [title] by [artist]auszugeben. - Eine
Video-Klasse, dieMediaerweitert und eineint duration-Eigenschaft (in Sekunden) hinzufügt. Verwenden Sie@overrideund überschreiben Sieplay(), um zuerst die Version der Elternklasse mitsuper.play()aufzurufen und dannDuration: [duration] secondsauszugeben.
- Eine
main.dart: Importieren Sie Ihre Mediendatei und demonstrieren Sie die überschriebenen Methoden:- Erstellen Sie ein
Media-Objekt mit dem Titel'Generic Content'und rufen Sieplay()auf. - Geben Sie eine Leerzeile aus.
- Erstellen Sie einen
Songmit dem Titel'Imagine'und dem Künstler'John Lennon', und rufen Sie dannplay()auf. - Geben Sie eine Leerzeile aus.
- Erstellen Sie ein
Videomit dem Titel'Dart Tutorial'und der Dauer360, und rufen Sie dannplay()auf.
- Erstellen Sie ein
Die @override-Annotation dokumentiert Ihre Absicht und hilft dabei, Fehler zu finden. Wenn Sie play() versehentlich als plya() schreiben würden, würde die Annotation Sie darauf hinweisen, dass eine solche Methode in der Elternklasse nicht existiert.
Erwartete Ausgabe:
Playing: Generic Content
Playing song: Imagine by John Lennon
Playing: Dart Tutorial
Duration: 360 secondsSpickzettel
Die @override-Annotation markiert Methoden, die absichtlich eine Methode einer Elternklasse ersetzen. Obwohl sie optional ist, bietet sie Sicherheit und Klarheit.
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}Vorteile von @override:
- Dokumentiert die Absicht – zeigt, dass die Methode in der Elternklasse existiert
- Erkennt Fehler – der Dart-Analyzer warnt, wenn die Elternmethode nicht existiert, was Tippfehler verhindert
Ohne @override erzeugen Tippfehler neue Methoden, anstatt Fehler zu melden:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // Tippfehler erzeugt neue Methode ohne Warnung
print('$name meows');
}
}Sie können die Version der Elternklasse mit super aufrufen:
@override
void play() {
super.play(); // Zuerst die Elternmethode aufrufen
print('Additional behavior');
}Probier es selbst
import 'media.dart';
void main() {
// TODO: Erstelle ein Media-Objekt mit dem Titel 'Generic Content' und rufe play() auf
// TODO: Drucke eine Leerzeile
// TODO: Erstelle einen Song mit dem Titel 'Imagine' und dem Künstler 'John Lennon', rufe dann play() auf
// TODO: Drucke eine Leerzeile
// TODO: Erstelle ein Video mit dem Titel 'Dart Tutorial' und der Dauer 360, rufe dann play() auf
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor