什么是类 和对象
类就是一类,归类,把我们身边的东西抽象出来,变成一个类型,比如全世界的人抽象成一个人类,然后具体的一个人,例如Bob,Tom这些具体的一个人,就是对象。
类 就像一个“蓝图”或“模板”,定义了对象的结构和行为。
还是那人类,来说,人这个类,就是一个模板,人类有什么?名字、有手脚等器官,能说话,能思考。所以,对于名字和年龄等等这些是属于人类的属性特征。对于说话,思考等属于人类的动作行为。所以,类就是把现实中的东西,提取出一个“类”出来,然后有了这个类,就可以去创建出一个个的对象,例如Jack,Jim等等的这些人。
上面说的类的属性(姓名,年龄),和类的行为(说话,思考),我们可以通过变量和函数来表示。
它描述了对象应该有哪些 属性(变量) 和 方法(函数)。
类是一个摸具,它不是一个具体的东西,就好比你做面包用的摸具,通过这个模具制造出一个个实体的面包。
人类的编程发展历史,一开始是没有“类”的概念的,例如C语言,没有类,只有函数,变量,各种的语句等等,这时候叫面向过程。随着软件的发展,功能越来越丰富,人们发现用买那些过程的编程语言来开发的时候,会出现很多重复的代码,而且代码管理混乱,不够层次感,没有调理。后来有人想出来,可以把编程的逻辑抽象成一个个的对象,和现实一样。就好比一个公司,一开始什么工作都老板亲历亲为,后来,老板招人了,他要做统计,就找财务,他要招人,就找人力。这样各司其职,是不是就条例清晰很多了。
对象 是类的一个 实例(Instance)。
当你用 new 或构造函数创建时,类就会生成一个对象。
对象是实际存在的,可以存储数据、调用方法。
类与对象的关系
- 类是 设计图,对象是 实际建造出来的房子。
- 一个类可以创建多个对象,每个对象有自己独立的数据。
- 所有对象共享类中定义的行为(方法)。

下面回到我们的dart中
我们将会学习如下的东西
Dart 是面向对象语言,所有对象都是类的实例。除了 Null,所有类都继承自 Object。
Dart 基于类 + Mixin 实现继承
单继承:每个类只有一个父类,但 Mixin 可复用多套类逻辑
扩展方法:无需改类 / 新建子类即可给类新增功能
类修饰符:控制其他库能否继承 / 实现该类
下面我们开始学习Dart中的类
类成员
类的成员,包括方法与变量,所谓成员,就是类里面的组成成员。
使用 . 访问实例成员;?. 空安全访问,避免空指针异常
下面是一个完整的例子,里面有创建类,通过类实例化对象,通过对象名调用成员
// 创建类 相当于创建一个模具
class Point {
double x, y;
Point(this.x, this.y);
// 实例方法:计算两点距离
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
// 通过Point类来创建对象p 对象才可以进行各种操作
var p = Point(2, 2);
// 读取实例变量(隐式 getter)
print(p.y); //2.0
// 调用实例方法
double dist = p.distanceTo(Point(4, 4));
print(dist); // 8.0
// ?. 空安全访问
Point? nullablePoint;
var a = nullablePoint?.y; // p为null,a直接赋值null,不抛异常
print(a); // null
}Code language: Dart (dart)

构造函数(Constructors)
普通构造函数
Dart和其他类C语言有点不应用,它还有一个命名构造函数,其他类C语言都是使用和类名同名的构造函数,Dart可以用和类名不同的名称来表示构造函数。
格式:类名() / 类名.标识符();
new 关键字可省略(Dart2+后才有的)
class Point {
double x, y; //两个变量 属于类成员 用来存储类的属性
// 默认构造 用来初始化上面两个变量 x y
Point(this.x, this.y);
// 命名构造 Point.fromJson 表示这个构造函数是通过json来初始化x y的
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']!;
}
void main() {
var p1 = Point(2, 2);//调用默认构造函数 传入2 2 然后初始化里面的x y p1的x是2 y是2
var p2 = Point.fromJson({'x': 1, 'y': 2}); //通过fromJson命名构造函数 传入json
// new 可写可不写,效果完全一致
var p3 = new Point(3, 3); //同样使用默认构造函数
print("p1:(${p1.x},${p1.y}), p2:(${p2.x},${p2.y}), p3:(${p3.x},${p3.y})");
//输出:p1:(2.0,2.0), p2:(1.0,2.0), p3:(3.0,3.0)
}Code language: Dart (dart)
常量构造 const
构造函数加 const,创建编译期常量;相同参数常量会复用同一个实例
class ImmutablePoint {
final double x, y;
// 常量构造:所有成员必须final,也就是构造函数有const修饰,则成员x, y 需要final
const ImmutablePoint(this.x, this.y);
}
void main() {
// 常量实例
var a = const ImmutablePoint(1, 1); //这里创建实例的时候,也需要const
var b = const ImmutablePoint(1, 1);
print(identical(a, b)); // true 同一个对象
var m = const ImmutablePoint(1, 1);
var n = const ImmutablePoint(2, 1);
print(identical(m, n)); // false x的值不同 对象就不同了
// 无const,普通对象,不共享实例
var c = ImmutablePoint(1, 1);
print(identical(a, c)); //false
// const上下文可省略内层const
const pointMap = {
'p1': [ImmutablePoint(0, 0)],
'p2': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)]
};
print(pointMap); //{p1: [Instance of 'ImmutablePoint'], p2: [Instance of 'ImmutablePoint', Instance of 'ImmutablePoint']}
print(identical(p1, p2)); // false
print(identical(p2, p3)); // false
print(identical(p1, p3)); // false
}Code language: Dart (dart)
常量构造入参完全一致才会复用同一个实例,任意参数不同则是两个独立对象
获取对象运行时类型 runtimeType
通过 对象.runtimeType 获取运行时类型;优先用类型判断运算符 is,而非 runtimeType 判等
class Point {
double x, y;
Point(this.x, this.y);
// 实例方法:计算两点距离
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
var p = Point(2, 3);
print("p 的类型:${p.runtimeType}"); // Point
// 推荐写法(稳定)
if (p is Point) {
print("p 是 Point 类型");
}
// 不推荐生产环境使用
if (p.runtimeType == Point) {
print("p 是 Point 类型 ");
}
}Code language: Dart (dart)
实例变量 Instance Variables
- 可空类型未初始化:默认
null;非空必须初始化 - 所有实例变量自动生成 getter;非 final / 无初始化 late final 自动生成 setter
- 普通实例变量初始化表达式不能访问 this;late 变量初始化可访问 this
- final 实例变量只能赋值一次:声明时 / 构造参数 / 初始化列表赋值
隐式 get/set
class Point {
double? x; // 初始null,自动get+set
double? y;
double z = 0; // 初始0
}
void main() {
var point = Point();
point.x = 4; // 调用隐式setter
assert(point.x == 4); // 调用隐式getter
assert(point.y == null);
print(point.z); // 0
}
Code language: JavaScript (javascript)
初始化表达式 this 访问限制
double globalX = 1.5;
class Point {
// 合法:访问外部全局变量,不依赖this
double? x = globalX;
// 报错:普通初始化不能用this
// double? y = this.x;
// 合法:late 初始化可访问this
late double? z = this.x;
// 合法:构造参数语法糖 this.x 不是初始化表达式
Point(this.x, this.y);
double? y;
}
void main() {
var p = Point(null, 5);
print(p.z); // null
}
Code language: JavaScript (javascript)
final 实例变量三种初始化方式
class ProfileMark {
// 方式1:声明直接初始化
final DateTime start = DateTime.now();
final String name;
// 方式2:构造参数赋值
ProfileMark(this.name);
// 方式3:构造初始化列表赋值 前面的命名构造函数 参数没传入 默认给''
ProfileMark.unnamed() : name = '';
}
void main() {
var m1 = ProfileMark("user1");
var m2 = ProfileMark.unnamed();
print(m1.name);
print(m2.name);
}
Code language: PHP (php)
隐式接口 Implicit interfaces
Dart 每个类自带隐式接口:包含自身所有实例成员。
implements:实现接口,必须重写接口全部方法extends:继承,复用父类实现- 私有变量
_xxx不会暴露到接口
1 实现单个接口
class Person {
final String _name;
Person(this._name);
// 接口公开方法
String greet(String who) => "Hello $who, I'm $_name";
}
// 实现Person接口,必须重写所有接口成员
class Impostor implements Person {
String get _name => "";
@override
String greet(String who) => "Hi $who, guess who?";
}
String greetBob(Person p) => p.greet("Bob");
void main() {
print(greetBob(Person("Kathy")));
print(greetBob(Impostor()));
}
Code language: PHP (php)
子类重写父类接口的时候,用@override来标注,和java类似,子类继承父类的时候用implements 关键字

2 实现多个接口
//抽象类
abstract class Comparable {
int compareTo(Object other);
}
//抽象类
abstract class Location {
double get x;
double get y;
}
//实现两个接口
class Point implements Comparable, Location {
@override
double x, y;
Point(this.x, this.y);
@override
int compareTo(Object other) {
if (other is Point) {
return (x + y).compareTo(other.x + other.y);
}
return -1;
}
}
void main() {
var p = Point(2, 3);
print(p.x);
print(p.compareTo(Point(1, 1)));
}
Code language: PHP (php)
@override
double x, y;
注解,表示:这两个属性是实现父接口 Location 里定义的抽象 getter。
类静态变量 & 静态方法 static
1. 静态变量 static(类变量,全局唯一)
- 属于类,不属于实例;延迟初始化,使用时才创建
- 常量静态变量推荐小驼峰命名
class Queue {
static const initialCapacity = 16; //静态变量
static int count = 0; //静态变量
Queue() {
count++;
}
}
void main() {
assert(Queue.initialCapacity == 16); //调用 就会创建 默认是16
Queue(); //让count+1
Queue();
print(Queue.count); // 2
}
Code language: JavaScript (javascript)
2. 静态方法 static(类方法)
- 无
this,不能访问实例成员;仅能访问静态变量 - 直接
类名.方法()调用 - 可作为编译期常量传入常量构造函数
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
// 静态方法:计算两点距离
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var dist = Point.distanceBetween(a, b);
print(dist); // ~2.828
}Code language: JavaScript (javascript)

静态方法属于类的,所以需要类名来调用,传入两个Point的实例。