字节笔记本

2026年3月22日

Dart 构造函数完全指南:默认、命名、常量、工厂构造函数详解

这篇文章将详细介绍 Dart 语言中的构造函数类型,包括默认构造函数、命名构造函数、常量构造函数、工厂构造函数等,并通过示例讲解构造函数的初始化列表、重定向和继承机制。

默认构造函数

dart
class Person {
  String name;
  int age;

  // 默认(无名)构造函数
  Person(this.name, this.age);
}

// 使用
var p = Person('张三', 25);

当没有显式定义构造函数时,Dart 会提供一个默认的无参构造函数。

命名构造函数

Dart 允许定义多个命名构造函数,类似于其他语言的函数重载:

dart
class Point {
  double x, y;

  Point(this.x, this.y);

  // 命名构造函数 - 从 JSON 创建
  Point.fromJson(Map<String, double> json)
      : x = json['x'],
        y = json['y'];

  // 命名构造函数 - 原点
  Point.origin()
      : x = 0,
        y = 0;
}

// 使用
var p1 = Point(3, 4);
var p2 = Point.fromJson({'x': 1, 'y': 2});
var p3 = Point.origin();

常量构造函数

使用 const 关键字修饰的构造函数,所有实例字段必须是 final 的:

dart
class ImmutablePoint {
  final double x;
  final double y;

  const ImmutablePoint(this.x, this.y);

  static final ImmutablePoint origin = const ImmutablePoint(0, 0);
}

// 编译时常量,所有 const 创建的相同参数对象是同一个实例
var p1 = const ImmutablePoint(1, 1);
var p2 = const ImmutablePoint(1, 1);
print(identical(p1, p2)); // true

工厂构造函数

工厂构造函数不会总是创建新实例,可以从缓存中返回已有实例:

dart
class Logger {
  final String name;
  bool _isInit = false;

  // 私有构造函数
  Logger._internal(this.name);

  // 工厂构造函数
  static final Map<String, Logger> _cache = {};

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

// 多次调用返回同一个实例
var logger1 = Logger('UI');
var logger2 = Logger('UI');
print(identical(logger1, logger2)); // true

工厂构造函数的关键特点:

  • 使用 factory 关键字声明
  • 不能使用 this 参数
  • 必须显式返回一个实例
  • 适合实现单例模式、缓存等场景

重定向构造函数

一个构造函数可以重定向到同类的另一个构造函数:

dart
class Rectangle {
  double width, height;

  Rectangle(this.width, this.height);

  // 重定向到主构造函数
  Rectangle.square(double size) : this(size, size);
}

初始化列表

构造函数体执行之前,可以初始化实例变量。初始化列表用冒号 : 分隔:

dart
class Rectangle {
  double width, height;

  // 通过初始化列表计算最终值
  Rectangle.fromJson(Map<String, double> json)
      : width = json['w'] * 2,
        height = json['h'] * 2 {
    print('Width: $width, Height: $height');
  }

  // 初始化列表中调用父类构造函数
  Rectangle.withColor(double w, double h, Color color)
      : width = w,
        height = h,
        super(color);
}

初始化列表的使用场景:

  • 设置 final 字段的值
  • 调用父类的构造函数
  • 使用 assert 进行参数校验
dart
class Point {
  final double x;
  final double y;

  Point({required double x, required double y})
      : assert(x >= 0),
        assert(y >= 0),
        this.x = x,
        this.y = y;
}

构造函数继承与 super

子类构造函数必须调用父类构造函数。如果父类没有无名无参构造函数,子类必须手动调用:

dart
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  String breed;

  // 显式调用父类构造函数
  Dog(String name, this.breed) : super(name);
}

如果父类有无名无参构造函数,子类会自动隐式调用。也可以使用级联调用:

dart
class View {
  View();
}

class MyView extends View {
  MyView() : super();
}

GetX 中的构造函数实践

在 GetX 框架中,Get.put()Get.lazyPut() 经常结合工厂模式使用:

dart
class Controller extends GetxController {
  static Controller get to => Get.find<Controller>();
}

// 使用工厂构造函数确保单例
class AppBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Controller());
  }
}

构造函数对比总结

类型关键字特点适用场景
默认构造函数类名最多一个基本实例化
命名构造函数类名.名称可定义多个不同初始化方式
常量构造函数const编译时常量不可变对象
工厂构造函数factory可返回缓存实例单例、缓存
重定向构造函数: this()转发到其他构造函数简化代码
分享: