Beginner · Null safety and object-oriented Dart · topic 6 of 50 · 35 min
Classes and constructors
Explanation
Why classes?
Apps deal with things: products, orders, users. A class describes one kind of thing: what data it has (fields) and what it can do (methods). An object (instance) is one actual thing created from the class. Every Flutter widget is a class too, so understanding classes is essential.
class Product {
final String name;
final int pricePaise;
int stock;
Product(this.name, this.pricePaise, this.stock); // this.field shorthand
bool get inStock => stock > 0; // getter
String get priceText => 'Rs ${pricePaise ~/ 100}';
void sell(int qty) {
if (qty > stock) throw StateError('Only $stock left');
stock -= qty;
}
@override
String toString() => 'Product($name, $priceText, stock: $stock)';
}
void main() {
final p = Product('Steel bottle', 49900, 3);
p.sell(2);
print(p); // Product(Steel bottle, Rs 499, stock: 1)
print(p.inStock); // true
}Fields marked final must be set once, in the constructor, and never change; that makes objects predictable. Plain fields (like stock above) can change. A getter such as inStock has no stored value: it is calculated every time you read it, so it can never be out of date.
Named constructors
A class can have several constructors with different names: ClassName.something(...). They are very common for creating objects from JSON or with preset values.
class Product {
final String name;
final int pricePaise;
Product({required this.name, required this.pricePaise});
Product.free(this.name) : pricePaise = 0; // named + initializer list
factory Product.fromJson(Map<String, dynamic> json) {
return Product(name: json['name'] as String, pricePaise: json['price'] as int);
}
}const constructors
If all fields are final and the constructor is marked const, you can create compile-time constant objects with const. Identical const objects are created once and shared. Flutter widgets use this a lot: const Text('Hello') and const SizedBox(height: 8) let Flutter skip rebuilding parts of the screen.
class Spacing {
final double value;
const Spacing(this.value);
}
void main() {
const a = Spacing(8);
const b = Spacing(8);
print(identical(a, b)); // true: one shared object
}factory constructors
A normal constructor always creates a new object of exactly that class. A factory constructor can run code first and return an existing object (a cache), or an object of a subtype. fromJson constructors are often factories because they parse and validate before creating.
Privacy with _
Dart has no public, private or protected keywords. A name that starts with an underscore (_balance, _calculate) is private to its library, which normally means its file. Code in other files cannot see it.
class Wallet {
int _balance = 0; // private field
int get balance => _balance; // read-only from outside
void add(int amount) {
if (amount <= 0) throw ArgumentError('amount must be positive');
_balance += amount;
}
}Common mistakes
- Forgetting to initialise final fields: "must be initialized". Use this.field in the constructor or an initializer list.
- Making fields public and mutable everywhere. Prefer final fields and methods that check the rules.
- Expecting _private to mean private to the class. It is private to the file.
- Missing const on constructors of simple immutable classes, losing the performance benefit in Flutter.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Classes and constructors · 1/6
final p = Product('Bottle', 49900, 3);A class groups fields and methods. Objects are created without the new keyword.
Prefer a video by a teacher? Find free videos on “dart classes constructors named factory const initializer list” on YouTube ↗
In real life: A product model from an API
A shopping app receives products as JSON. The Product class has final fields, a const constructor for tests and previews, a factory Product.fromJson that reads and checks the map, and getters for formatted prices. Every screen uses the same class, so formatting and validation are consistent.
class Product {
final int id;
final String name;
final int pricePaise;
const Product({required this.id, required this.name, required this.pricePaise});
factory Product.fromJson(Map<String, dynamic> j) =>
Product(id: j['id'] as int, name: j['name'] as String, pricePaise: j['price_paise'] as int);
String get price => 'Rs ${(pricePaise / 100).toStringAsFixed(2)}';
}
void main() {
final p = Product.fromJson({'id': 7, 'name': 'Kurta', 'price_paise': 89900});
print('${p.name}: ${p.price}'); // Kurta: Rs 899.00
}Practice (0/3 done)
What does this print? class Box { final int w, h; const Box(this.w, this.h); int get area => w * h; } void main() => print(Box(3, 5).area);
Which constructor kind can return an existing cached object instead of a new one?
Write a class BankAccount with a private _balance, a required named holder, a getter balance, deposit and withdraw methods that throw on invalid amounts or insufficient balance, a named constructor BankAccount.zero(holder), and a toString. Use it in main, including a failed withdrawal caught with try/catch.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Inheritance, interfaces, mixins and extensionsNull safety and object-oriented Dart · same module
- Dart 3: enums, records, patterns and sealed classesNull safety and object-oriented Dart · same module
- Classes, objects and constructorsC# and .NET · Classes and objects
- ClassesJavaScript Programming (language in depth) · Scope, this, prototypes and classes
- Constructors and thisJava Programming (Core to Spring Boot) · Classes and objects
- Interview questions: DartFlutter careers and interviews
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
How do you make a field private in Dart?
Answer: Start its name with _
Underscore names are library-private.
What is an initializer list?
Answer: Code after : in a constructor that sets fields before the body runs
For example : pricePaise = 0.
Why do Flutter widgets often use const constructors?
Answer: Constant widgets are created once and can be skipped during rebuilds
const saves work at run time.
What does identical(a, b) check?
Answer: Whether a and b are the very same object
Identity, not equality.
What does : this(name, 0m) after a constructor header do?Related
Answer: Calls another constructor of the same class first
It chains to another constructor to reuse its setup code.
What makes a class field private?Related
What is the return type of a constructor?Related
Which constructor type can return a cached instance?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Null safety and object-oriented Dart” before its exam: Inheritance, interfaces, mixins and extensions, Dart 3: enums, records, patterns and sealed classes.
- Module 2 exam: Null safety and object-oriented Dart · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Async Dart and packages. 50 topics left in the course before the final exam.