ZetCode

Dart 对象

最后修改日期:2025 年 6 月 4 日

本 Dart 对象教程探讨了如何在 Dart 编程语言中使用对象。对象是 Dart 程序的构建块,它们结合了数据和行为,以创建模块化、可重用的代码。

理解对象

在 Dart 中,对象是程序的基本单元,封装了数据和方法。数据,也称为实例变量,以及方法,也称为成员函数,统称为对象的成员。对象通过它们的方法相互交互,从而实现数据处理和通信。

创建对象涉及两个步骤:定义类和实例化它。类充当蓝图,概述了该类所有对象共享的状态和行为。对象,或实例,是使用 new 关键字在运行时从类创建的,而 new 关键字在 Dart 2.0 及更高版本中是可选的。我们使用点 (.) 运算符来访问对象的实例变量或方法。

面向对象编程 (OOP) 是一种利用对象及其交互来设计健壮的应用程序和程序的范例。

Dart 对象

在 Dart 中,一切皆对象,包括数字和字符串等字面量,这使 Dart 与许多其他编程语言区分开来。

main.dart
class Being {}

void main() {
  var b = Being();

  print(b.hashCode);
  print("falcon".toUpperCase());
  print(2.isNegative);

  print(b.runtimeType);
  print(2.runtimeType);
}

此示例演示了在 Dart 中使用各种对象。

class Being {}

class 关键字定义了对象的模板。在这里,Being 类是空的,但仍然是功能性的。

var b = Being();

创建了一个新的 Being 实例。在现代 Dart 中,new 关键字是可选的。

print(b.hashCode);

即使是空对象也继承了 Dart 的 Object 类的方法和属性,例如 hashCode

print("falcon".toUpperCase());

字符串字面量 "falcon" 是一个具有 toUpperCase 等方法的对象,展示了 Dart 的面向对象特性。

print(2.isNegative);

数字字面量,例如 2,也是具有 isNegative 等属性的对象。

print(b.runtimeType);
print(2.runtimeType);

runtimeType 属性会在运行时显示每个对象的类型。

$ dart main.dart
511903303
FALCON
false
Being
int

Dart 对象属性

对象属性,或实例变量,用于存储每个类实例特有的数据。每个对象都维护这些变量的独立副本。Dart 会自动为所有实例变量生成 getter 方法,并为非 final 变量生成 setter 方法。

main.dart
class Person {
  String? name;
  String? occupation;
}

void main() {
  var p1 = Person();
  p1.name = "John Doe";
  p1.occupation = "gardener";

  var p2 = Person();
  p2.name = "Roger Roe";
  p2.occupation = "driver";

  print("${p1.name} is a ${p1.occupation}");
  print("${p2.name} is a ${p2.occupation}");
}

此示例定义了一个具有两个属性:nameoccupationPerson 类。

var p1 = Person();
p1.name = "John Doe";
p1.occupation = "gardener";

创建了一个 Person 对象,并通过点运算符设置了其属性。

var p2 = Person();
p2.name = "Roger Roe";
p2.occupation = "driver";

创建了第二个、唯一的 Person 对象,并设置了不同的属性值。

print("${p1.name} is a ${p1.occupation}");
print("${p2.name} is a ${p2.occupation}");

打印了两个对象的属性,展示了它们各自的状态。

$ dart main.dart
John Doe is a gardener
Roger Roe is a driver

Dart 级联运算符

级联运算符 (..) 允许以简洁的方式对同一对象执行多个操作,从而提高了代码的可读性。

main.dart
class User {
  String? fname;
  String? lname;
  String? occupation;
  @override
  String toString() => "$fname $lname is a $occupation";
}

void main() {
  var u = User()
    ..fname = "Roger"
    ..lname = "Roe"
    ..occupation = "driver";

  print(u);
}

此示例使用级联运算符在单个表达式中初始化 User 对象的属性。

$ dart main.dart
Roger Roe is a driver

Dart 对象方法

方法是在类中定义的函数,它们操作对象的属性,从而促进代码的模块化和可重用性。

main.dart
import 'dart:math';

class Circle {
  int radius;

  Circle(this.radius);

  double area() => pi * radius * radius;
}

void main() {
  var c = Circle(5);
  print(c.area());
}

此示例定义了一个具有 area 方法来计算圆面积的 Circle 类。

double area() => pi * radius * radius;

area 方法使用 dart:math 库中的 pi 常量来计算面积。

var c = Circle(5);

创建了一个半径为 5 的 Circle 对象。

print(c.area());

使用点运算符调用 area 方法来计算并打印面积。

$ dart main.dart
78.53981633974483

Dart 对象构造函数

构造函数是在创建对象时自动调用的特殊方法,用于初始化对象的状态。Dart 支持命名构造函数和工厂构造函数,它们不返回值。

命名构造函数共享类的名称,通常用于直接初始化。

main.dart
class User {
  String name;
  String occupation;

  User(this.name, this.occupation);
}

void main() {
  var u1 = User("John Doe", "gardener");
  var u2 = User("Roger Roe", "driver");

  print("${u1.name} is a ${u1.occupation}");
  print("${u2.name} is a ${u2.occupation}");
}

此示例使用命名构造函数来初始化 User 对象的属性。

User(this.name, this.occupation);

构造函数使用自动初始化程序来设置 nameoccupation 属性。

var u1 = User("John Doe", "gardener");

创建了一个 User 对象,并将值传递给构造函数。

$ dart main.dart
John Doe is a gardener
Roger Roe is a driver

工厂构造函数,使用 factory 关键字定义,允许自定义对象创建逻辑,例如缓存或条件实例化。它们可以返回现有对象,并且在设计模式中很有用。

main.dart
import 'dart:math';

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(4);
    if (type == 'square') return Square(4);
    if (type == 'triangle') return Triangle(4);
    throw Exception("Unknown shape");
  }
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

class Triangle implements Shape {
  final num side;
  Triangle(this.side);
  num get area => pow(side, 2) / 2;
}

void main() {
  print(Shape('circle').area);
  print(Shape('square').area);
  print(Shape('triangle').area);
}

此示例在抽象 Shape 类中使用工厂构造函数,根据类型参数创建不同的形状。

$ dart main.dart
50.26548245743669
16
8.0

Dart toString 方法

每个 Dart 对象都从 Object 类继承 toString 方法,该方法提供人类可读的字符串表示形式。对对象调用 print 会隐式调用 toString

main.dart
class User {
  String name;
  String occupation;

  User(this.name, this.occupation);

  @override
  String toString() => "$name is a $occupation";
}

void main() {
  var u1 = User("John Doe", "gardener");
  var u2 = User("Roger Roe", "driver");

  print(u1);
  print(u2);
}

此示例在 User 类中重写了 toString 方法,以提供自定义的字符串表示形式。

@override
String toString() => "$name is a $occupation";

重写的 toString 方法返回一个格式化的字符串,其中包含用户的姓名和职业。

print(u1);
print(u2);

打印对象会自动调用它们的 toString 方法。

$ dart main.dart
John Doe is a gardener
Roger Roe is a driver

Dart 自动初始化程序

Dart 支持使用自动初始化程序的简洁构造函数语法,这可以简化属性初始化,而无需显式的赋值语句。

main.dart
class User {
  String name;
  String occupation;

  User(this.name, this.occupation);
}

void main() {
  var u1 = User("John Doe", "gardener");
  var u2 = User("Roger Roe", "driver");

  print("${u1.name} is a ${u1.occupation}");
  print("${u2.name} is a ${u2.occupation}");
}

此示例在 User 类的构造函数中演示了自动初始化程序,推断数据类型并减少了样板代码。

Dart 命名参数

命名参数,用花括号 {} 表示,允许灵活的构造函数调用,其中参数通过名称指定,从而提高了代码的清晰度。

main.dart
class User {
  String? name;
  String? occupation;

  User({this.name, this.occupation});

  @override
  String toString() => "$name is a $occupation";
}

void main() {
  var u1 = User(name: "John Doe", occupation: "gardener");
  print(u1);
}

此示例使用命名参数初始化 User 对象,使代码更具可读性和灵活性。

Dart 对象继承

继承允许新类建立在现有类的基础上,创建派生类来扩展或覆盖基类的功能。Dart 使用 extends 关键字进行继承。

main.dart
class Being {
  static int count = 0;

  Being() {
    count++;
    print("Being is created");
  }

  void getCount() => print("There are $count Beings\n");
}

class Human extends Being {
  Human() {
    print("Human is created");
  }
}

class Animal extends Being {
  Animal() {
    print("Animal is created");
  }
}

class Dog extends Animal {
  Dog() {
    print("Dog is created");
  }
}

void main() {
  Human();
  var dog = Dog();
  dog.getCount();
}

此示例演示了一个类层次结构,其中 HumanAnimal 继承自 Being,而 Dog 继承自 Animal。一个静态变量用于跟踪实例计数。

static int count = 0;

静态 count 变量在 Being 类及其子类的所有实例之间共享。

Being() {
  count++;
  print("Being is created");
}

Being 构造函数在每次创建实例时递增计数并打印一条消息。

class Animal extends Being {
...
class Dog extends Animal {
...

AnimalDog 类分别继承自它们的父类,形成多级层次结构。

Human();
var dog = Dog();
dog.getCount();

创建了 HumanDog 的实例,并且 getCount 方法显示了 Being 实例的总数。

$ dart main.dart
Being is created
Human is created
Being is created
Animal is created
Dog is created
There are 2 Beings

Dart 检查类型

Dart 的 is 关键字在运行时检查对象的类型,这对于动态代码中的类型验证很有用。

main.dart
class Person {}

class Student {}

void main() {
  var p = Person();
  var s = Student();

  print(p is Person);
  print(s is Person);
  print(p is Object);
  print(s is Object);

  print(2 is int);
  print(2 is Object);
}

此示例使用 is 关键字检查各种对象的类型。

print(p is Person);

这会检查 p 是否是 Person 的实例,结果返回 true。

print(s is Person);

这会检查 s 是否是 Person,结果返回 false,因为 sStudent

print(2 is Object);

由于所有 Dart 对象都继承自 Object,因此此检查对于数字字面量 2 返回 true。

$ dart main.dart
true
false
true
true
true
true

Dart Getter 和 Setter

Dart 允许显式定义 getter 和 setter 来控制对对象属性的访问,从而提供封装和验证逻辑。

main.dart
class Account {
  double _balance = 0.0;

  double get balance => _balance;

  set balance(double value) {
    if (value >= 0) {
      _balance = value;
    } else {
      throw Exception("Balance cannot be negative");
    }
  }
}

void main() {
  var account = Account();
  account.balance = 100.0;
  print("Balance: ${account.balance}");

  try {
    account.balance = -50.0;
  } catch (e) {
    print(e);
  }
}

此示例定义了一个 Account 类,其中包含一个私有的 _balance 属性,该属性通过 getter 和 setter 方法进行访问。

double get balance => _balance;

getter 返回私有的 _balance 值。

set balance(double value) {
  if (value >= 0) {
    _balance = value;
  } else {
    throw Exception("Balance cannot be negative");
  }
}

setter 验证余额是否为非负数,然后再进行更新。

$ dart main.dart
Balance: 100.0
Exception: Balance cannot be negative

Dart 方法重写

方法重写允许子类提供其超类中定义的方法的特定实现,从而实现多态行为。

main.dart
class Animal {
  void makeSound() => print("Some generic sound");
}

class Dog extends Animal {
  @override
  void makeSound() => print("Woof!");
}

class Cat extends Animal {
  @override
  void makeSound() => print("Meow!");
}

void main() {
  var dog = Dog();
  var cat = Cat();

  dog.makeSound();
  cat.makeSound();
}

此示例演示了在具有 AnimalDogCat 的类层次结构中进行方法重写。

@override
void makeSound() => print("Woof!");

Dog 类重写了 makeSound 方法以提供特定实现。

$ dart main.dart
Woof!
Meow!

Dart Mixins

Dart 中的 Mixin 允许通过添加功能到类而不使用继承来实现代码重用,从而促进了模块化和灵活性。

main.dart
mixin Flyable {
  void fly() => print("Flying...");
}

class Bird with Flyable {
  String name;

  Bird(this.name);
}

void main() {
  var eagle = Bird("Eagle");
  eagle.fly();
  print("${eagle.name} is soaring high!");
}

此示例使用 Flyable mixin 为 Bird 类添加飞行行为。

mixin Flyable {
  void fly() => print("Flying...");
}

Flyable mixin 定义了一个 fly 方法,可以与任何类共享。

class Bird with Flyable {

Bird 类使用 with 关键字合并了 Flyable mixin。

$ dart main.dart
Flying...
Eagle is soaring high!

Dart 抽象类

Dart 中的抽象类不能被实例化,用于定义接口或为子类提供共享功能。

main.dart
abstract class Vehicle {
  void startEngine();
}

class Car extends Vehicle {
  @override
  void startEngine() => print("Car engine started");
}

class Bike extends Vehicle {
  @override
  void startEngine() => print("Bike engine started");
}

void main() {
  var car = Car();
  var bike = Bike();

  car.startEngine();
  bike.startEngine();
}

此示例定义了一个抽象 Vehicle 类,以及具体的子类 CarBike

abstract class Vehicle {
  void startEngine();
}

抽象 Vehicle 类声明了一个 startEngine 方法,子类必须实现该方法。

$ dart main.dart
Car engine started
Bike engine started

来源

Dart 类 - 语言参考

本教程探讨了使用 Dart 中对象的基础知识,包括属性、方法、构造函数、继承等。

作者

Jan Bodnar 是一位充满热情的程序员,拥有十多年的编程教学和写作经验。自 2007 年以来,他撰写了超过 1,400 篇文章和 8 本电子书,分享他在各种编程语言方面的专业知识。

探索 所有 Dart 教程