The final Class Keyword
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 40 of 110.
Sometimes you want to prevent a class from being extended. The final keyword, when applied to a class, stops any other class from inheriting from it.
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// This would cause a compile-time error:
// class CustomConnection extends DatabaseConnection { }Marking a class as final is useful when extending it could break its intended behavior or security guarantees. For example, a class that manages sensitive resources might need to ensure its methods aren't overridden in unexpected ways.
Dart 3 also introduced related modifiers: base forces subclasses to use extends (not implements), and sealed restricts inheritance to the same library. For now, focus on final as the simplest way to lock down a class completely.
Use final classes when you're certain the class design is complete and inheritance would only cause problems. However, don't overuse it - most classes benefit from remaining open for extension.
Challenge
EasyLet's build a secure configuration system that demonstrates when and why you'd want to prevent a class from being extended. You'll create a final class that manages application settings, ensuring its behavior can't be altered through inheritance.
You'll organize your code into two files:
config.dart: Define your configuration classes here:- A
final class AppConfigthat cannot be extended. It should have aString appNameandString versionproperty, a constructor that takes both values, and a methoddisplay()that prints[appName] v[version] - A regular (non-final)
Featureclass with aString nameandbool enabledproperty, a constructor for both, and a methodstatus()that prints[name]: [enabled ? 'ON' : 'OFF'] - An
ExperimentalFeatureclass that extendsFeatureand adds aString warningproperty. Overridestatus()using@overrideto first call the parent's version withsuper.status(), then printWarning: [warning]
- A
main.dart: Import your config file and demonstrate the difference between final and regular classes:- Create an
AppConfigwith appName'MyApp'and version'2.0.1', then calldisplay() - Print an empty line
- Create a
Featurewith name'Dark Mode'and enabledtrue, then callstatus() - Print an empty line
- Create an
ExperimentalFeaturewith name'AI Assistant', enabledfalse, and warning'May be unstable', then callstatus()
- Create an
Notice how AppConfig is marked as final because its configuration behavior should remain consistent and secure - no subclass should be able to alter how settings are managed. Meanwhile, Feature remains open for extension, allowing ExperimentalFeature to add specialized behavior.
Expected output:
MyApp v2.0.1
Dark Mode: ON
AI Assistant: OFF
Warning: May be unstableCheat sheet
The final keyword prevents a class from being extended:
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// This would cause a compile-time error:
// class CustomConnection extends DatabaseConnection { }Use final classes when extending them could break intended behavior or security guarantees. Most classes should remain open for extension unless there's a specific reason to lock them down.
Dart 3 also provides base (forces subclasses to use extends) and sealed (restricts inheritance to the same library) modifiers.
Try it yourself
import 'config.dart';
void main() {
// TODO: Create an AppConfig with appName 'MyApp' and version '2.0.1'
// Then call display()
// TODO: Print an empty line
// TODO: Create a Feature with name 'Dark Mode' and enabled true
// Then call status()
// TODO: Print an empty line
// TODO: Create an ExperimentalFeature with name 'AI Assistant',
// enabled false, and warning 'May be unstable'
// Then call status()
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor