Skip to main content
A class in Dart is a blueprint for creating objects, encapsulating state (fields) and behavior (methods). Dart is an object-oriented language featuring mixin-based inheritance, where every object is an instance of a class, and all classes except Null descend from Object.

Class Declaration

A class is defined using the class keyword. The body is enclosed in curly braces {} and contains fields, constructors, and methods.
class Point {
  // Instance variables (Fields)
  double x;
  double y;

  // Constructor
  Point(this.x, this.y);

  // Method
  double distanceToOrigin() {
    return 0.0; // Implementation logic
  }
}

Instance Variables

Instance variables, or fields, store the state of an object.
  • Null Safety: Non-nullable fields must be initialized inline, via a constructor, or marked late.
  • Visibility: Dart does not use public, private, or protected keywords. Members are public by default. Prefixing an identifier with an underscore (_) makes it library-private.
class Configuration {
  String apiKey;          // Non-nullable, must be initialized
  String? description;    // Nullable
  late final int _cache;  // Private, late initialization

  Configuration(this.apiKey) {
    // Late variables must be assigned before access
    _cache = DateTime.now().millisecondsSinceEpoch;
  }
}

Constructors

Constructors are special functions responsible for initializing an object.

Generative Constructors

The most common form, used to create a new instance. Dart provides syntactic sugar (this.variableName) to assign arguments directly to fields.
class Vector {
  final int x, y;

  // Standard generative constructor
  Vector(this.x, this.y);
}

Named Constructors

Classes can define multiple constructors using named identifiers to clarify the purpose of the instantiation.
class Vector {
  double x, y;

  Vector(this.x, this.y);

  // Named constructor
  Vector.origin()
      : x = 0,
        y = 0;
}

Initializer Lists

Execution occurs before the constructor body runs. This is required for initializing final fields that are not handled by the initializing formal parameters.
class Rect {
  final int width;
  final int height;
  final int area;

  Rect(this.width, this.height) : area = width * height;
}

Factory Constructors

Marked with the factory keyword, these constructors do not necessarily create a new instance of the class. They may return an existing instance from a cache or an instance of a subtype.
class Logger {
  static final Map<String, Logger> _cache = {};

  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  Logger._internal(this.name);
  final String name;
}

Constant Constructors

If a class produces objects that never change, the constructor can be marked const. All instance variables must be final.
class ImmutablePoint {
  final double x, y;
  const ImmutablePoint(this.x, this.y);
}

Methods

Methods define the behavior of the object.
  • Instance Methods: Operate on instance variables and have access to this.
  • Getters and Setters: Special methods that provide read and write access to object properties. Defined using get and set keywords.
  • Static Methods: Defined with static. They operate on the class itself rather than an instance and do not have access to this.
class Circle {
  double radius;

  Circle(this.radius);

  // Getter
  double get area => 3.14 * radius * radius;

  // Setter
  set diameter(double value) => radius = value / 2;

  // Static method
  static double calculateArea(double r) => 3.14 * r * r;
}

Inheritance

Dart supports single inheritance using the extends keyword. A subclass inherits the members of the superclass.
  • Overriding: Subclasses can override instance methods, getters, and setters using the @override annotation.
  • Super: The super keyword references the immediate parent class.
  • Super Parameters: Constructors can avoid manually passing parameters to the superclass by using super.parameterName. Type annotations are inferred from the super constructor and are not permitted on the subclass parameter.
class Spacecraft {
  String name;
  DateTime? launchDate;

  Spacecraft(this.name, this.launchDate);

  void describe() => print('Spacecraft: $name');
}

class Orbiter extends Spacecraft {
  double altitude;

  // Types for 'name' and 'launchDate' are inferred from the Spacecraft constructor
  Orbiter(super.name, super.launchDate, this.altitude);

  @override
  void describe() {
    super.describe();
    print('Altitude: $altitude');
  }
}

Abstract Classes

Defined using the abstract keyword, these classes cannot be instantiated directly. They are useful for defining interfaces or base classes with partial implementation. Abstract classes can contain abstract methods (methods without a body).
abstract class Shape {
  // Abstract method
  double calculateArea();
  
  // Concrete method
  void printType() => print('I am a shape');
}

Implicit Interfaces

Every class in Dart implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. A class can implement these interfaces using the implements keyword, enforcing the overriding of all members.
// Person acts as an interface here
class Person {
  final String name;
  Person(this.name);
  String greet(String who) => 'Hello, $who. I am $name.';
}

class Impostor implements Person {
  @override
  String get name => '';

  @override
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

Mixins

Mixins are a way of reusing a class’s code in multiple class hierarchies. They are declared using mixin and applied using with.
mixin Musical {
  bool canPlayPiano = false;
  void entertain() => print('Playing music');
}

// Assumes Person is defined as in the previous section
class Performer extends Person with Musical {
  Performer(super.name);
}
Master Dart with Deep Grasping Methodology!Learn More