news 2026/10/19 13:06:34

YCBlogs Flutter 系列:Dart 面向对象编程全面详解——从类、构造器到继承、泛型与访问控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YCBlogs Flutter 系列:Dart 面向对象编程全面详解——从类、构造器到继承、泛型与访问控制
  • 教程
  • 技术博客
  • 文档

【免费下载链接】YCBlogs

技术博客笔记大汇总,包括Java基础,线程,并发,数据结构;Android技术博客等等;常用设计模式;常见的算法;网络协议知识点;部分flutter笔记;还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!转载请注明出处,谢谢!

项目地址:https://gitcode.com/gh_mirrors/yc/YCBlogs
点击查看免费下载

本篇技术指南以 YCBlogs 仓库中 flutter/01.Dart基础/02.Dart面向对象介绍.md 为骨架,系统讲解 Dart 的面向对象特性:类的定义与实例化、三种构造函数形态、继承与 super/this 重定向、方法重写与重载、抽象类、私有化访问控制、静态成员与泛型。文中所有代码均可直接复制运行,并补充了仓库中 flutter/01.Dart基础/01.Dart基础类型介绍.md 与 flutter/01.Dart基础/05.Dart实践注意事项.md 的关联知识点。读完本文,你将完整掌握 Dart 面向对象的语法细节,并能在 Flutter 的 Widget 体系(如StatefulWidget/StatelessWidget、abstract class、泛型容器)中熟练运用这些能力。

01. 类简单介绍:创建类与实例化

在 Dart 中,类(Class)是一切面向对象编程的基石,也是 Flutter 中 Widget 体系的基本单元。创建类和创建类的实例非常简单,使用class关键字声明类,使用new关键字(现代 Dart 中new可省略)创建实例:

void test1() { Dog d = new Dog(); } class Dog { }

如果类需要持有数据,可以声明成员变量,并通过构造函数传入初始值:

var cat = new Cat("逗比", 12); class Cat { String name; int age; Cat(String name, int age) { this.name = name; this.age = age; } }

关于类与实例,有几个关键认知需要建立:

  • 一切皆继承自 Object:与仓库 flutter/01.Dart基础/01.Dart基础类型介绍.md 中 1.3 节所述一致,Object是 Dart 所有对象的根基类,所有类型(包括Function和Null)都是Object的子类,所以任何类型的数据都可以赋值给Object声明的对象。
  • 变量自带 getter/setter:Dart 不需要像 Java 那样手动编写getXxx/setXxx,所有基础类型、类等都继承自Object,默认值为null,自带 getter 和 setter;而final或const修饰的变量只有 getter 没有 setter(详见 flutter/01.Dart基础/01.Dart基础类型介绍.md 1.2 节)。
  • 与 Flutter Widget 的关系:在 Flutter 中,几乎所有的 UI 单元都是类。例如仓库 flutter/02.基础知识/00.Flutter案例介绍.md 中class TestHello extends StatelessWidget、class MyHomePage extends StatefulWidget,本质都是"定义类 → 继承基类 → 覆写 build 方法"的过程,这正是 Dart 面向对象在真实项目中的直接体现。

02. 构造函数:普通、命名与重定向

构造函数用于初始化对象的成员变量。Dart 的构造函数远比 Java 灵活,除了最常见的普通构造函数,还支持命名构造函数、参数初始化列表与重定向构造函数。

2.1 普通构造函数

最基本的写法是显式声明构造函数并逐一赋值:

var cat = new Cat("逗比", 12); class Cat { String name; int age; Cat(String name, int age) { this.name = name; this.age = age; } }

Dart 提供了一种更简洁的语法糖——this.参数形式:构造参数直接用this.name声明,等价于上面的显式赋值:

class Dog { String name; int age; Dog(this.name, this.age); }

这种写法在仓库多处出现,例如 flutter/01.Dart基础/01.Dart基础类型介绍.md 6.1 节枚举示例中的Dog(this.name, this.age, this.state)。

2.2 命名构造函数

普通构造函数只能有一个(同名),为了表达"多种创建意图",Dart 引入了命名构造函数:类名.名称(...)。这比 Java 中通过静态工厂方法模拟的方式更直观,也让不同构造方式的意图更加清晰:

Map map = new Map(); map['name'] = "哈巴狗"; map['age'] = 5; Dog d = new Dog.newBorn(map); class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn(Map json) { name = json['name']; age = json['age']; } }

命名构造函数非常适合"从不同数据源创建对象"的场景,比如从Map、JSON、数据库记录等构建实体。上述代码中Dog.newBorn(Map json)就是典型的"反序列化工厂"用法。

2.3 重定向构造函数(this 调用)

构造函数之间可以互相委托:通过this关键字,在冒号(:)之后调用同一个类中的其他构造函数,称为重定向构造函数。下面定义了Pug.small和Pug.large两个命名构造函数,它们只接收名字,然后重定向到默认构造函数,统一由默认构造函数完成真正的初始化:

Pug p = new Pug.small('哈巴狗'); print(p.name); class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = '逗比哈巴狗'; age = 0; } } class Pug extends Dog { Pug(String name, int age): super(name, age); Pug.small(String name): this(name, 1); Pug.large(String name): this(name, 3); }

2.4 构造函数在 Flutter 源码中的应用

Flutter 框架大量使用命名构造函数与this参数语法。仓库 flutter/03.原理分析/03.Widget原理详细分析.md 中展示了Opacity的源码:

class Opacity extends SingleChildRenderObjectWidget { const Opacity({ Key key, @required this.opacity, Widget child, }) : super(key: key, child: child); final double opacity; // 属性是 final,构造后不可变 ... }

这里同时展示了三个要点:@required this.opacity的this.参数语法、const构造函数(编译期常量)、以及: super(...)初始化列表调用父类构造函数。这也印证了 Dart 面向对象语法是理解 Flutter 框架源码的前提。

03. 继承类:extends、super 与 this 重定向

Dart 是单继承语言,使用extends关键字继承其他类。

3.1 基本继承

Pug类继承Dog类,通过super关键字调用父类的构造函数:

Pug p = new Pug('逗比哈巴狗', 5); print(p.name); class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } } class Pug extends Dog { Pug(String name, int age): super(name, age); }

注意,如果父类没有默认的无参构造函数,子类构造函数必须通过super(...)显式调用父类构造函数,否则无法编译。

3.2 子类内构造函数重定向

除了调用父类构造函数,子类构造函数也可以通过this在冒号之后重定向到自身的其他构造函数(最终仍会经由某个构造函数调用super):

Pug p = new Pug.small('哈巴狗'); print(p.name); class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = '逗比哈巴狗'; age = 0; } } class Pug extends Dog { Pug(String name, int age): super(name, age); Pug.small(String name): this(name, 1); Pug.large(String name): this(name, 3); }

这种"重定向 + 统一初始化"的模式,可以显著减少重复代码:所有构造入口最终都汇聚到主构造函数,初始化逻辑只写一遍。

3.3 继承在 Flutter 中的应用

Flutter 的 Widget 体系本身就是一棵巨大的继承树,仓库 flutter/03.原理分析/03.Widget原理详细分析.md 给出了清晰的继承链示例:

class Opacity extends SingleChildRenderObjectWidget { ... } abstract class SingleChildRenderObjectWidget extends RenderObjectWidget { ... } abstract class RenderObjectWidget extends Widget { ... }

即Opacity → SingleChildRenderObjectWidget → RenderObjectWidget → Widget,每层通过super向上传递key、child等配置。理解extends/super是阅读 Flutter 框架源码的必备技能。

04. 重载与重写:Dart 的差异化设计

4.1 方法重写(@override)

子类可以重写父类方法,并用@override注解明确标注。@override是 Dart 内置的三个元数据注解之一(另外两个是@deprecated与@proxy,详见 flutter/01.Dart基础/01.Dart基础类型介绍.md 6.2 节)。下面示例中,Pug重写了父类Dog的bark()方法,最终打印值是"你真是个逗比!":

Pug p = new Pug(); print(p.bark()); class Dog { bark() { print('Bow Wow'); } } class Pug extends Dog { @override bark() { print('你真是个逗比!'); } }

在 Flutter 中,@override随处可见:StatefulWidget需要重写createState(),State需要重写build(BuildContext context),仓库 flutter/02.基础知识/00.Flutter案例介绍.md 中的_MyHomePageState正是通过@override Widget build(...)完成 UI 构建。

4.2 方法重载:Dart 与传统语言不同

原文档中"方法重载"部分留白,这里补充关键事实:Dart 不支持 Java/C++ 那种"同名不同参数列表"的传统重载(同作用域内方法名唯一)。Dart 的解决方案是:

  • 可选位置参数:void f(int a, [int b]),b可不传;
  • 命名参数:参数用花括号{}包裹,调用时必须指定参数名,如仓库 flutter/01.Dart基础/01.Dart基础类型介绍.md 4.2 节所述:"如果你在调用命名参数的函数时,没有指定参数的名字,则会提示红色报错,无法通过编译";
  • 参数默认值:可给命名参数提供默认值,如fullName(String firstName, {String lastName = '逗比'})(见 4.3 节)。

因此,在 Dart 中实现"多形态方法"的正确姿势是可选参数 + 默认值,而不是声明多个同名方法。

05. 抽象类:定义契约与规范

使用abstract关键字声明抽象类。抽象类可以包含只有签名、没有实现的抽象方法,也可以包含已实现的方法。抽象类不能直接实例化,必须由子类继承并实现全部抽象方法:

abstract class AbstractDog { void eat(); void _hiddenMethod(); } class SmallDog extends AbstractDog { @override void _hiddenMethod() { } @override void eat() { } }

关键点总结:

  • 与 Java 不同,Dart 的抽象方法不需要abstract关键字修饰,只要"只有方法签名、没有方法体"即为抽象方法;
  • 抽象方法中_hiddenMethod()以_开头,说明抽象方法同样遵循 Dart 的私有命名规则(详见下一节);
  • 非抽象子类必须实现父类的所有抽象方法,否则子类也只能是抽象的;
  • implements与extends的差异:implements是"实现接口",子类需要重写接口声明的所有成员(包括已实现方法);extends是"继承类",只需实现抽象方法并可复用父类实现。

抽象类是 Flutter 框架层与业务层之间最重要的契约工具。仓库 flutter/03.原理分析/03.Widget原理详细分析.md 中Widget本身就是抽象类:

abstract class Widget extends DiagnosticableTree { const Widget({ this.key }); ... @protected @factory Element createElement(); ... }

它定义了所有 Widget 必须实现的createElement()抽象方法;StatelessWidget、StatefulWidget都是它的抽象子类,分别实现StatelessElement createElement()与StatefulElement createElement()。这就是"抽象类定义骨架、子类填充实现"的典型架构模式。

06. 访问权限:Dart 的私有化规则

6.1_前缀私有化

Dart没有public/private/protected关键字。默认情况下,类中的所有属性和方法都是 public 的;只需要在名字前加下划线_,即可实现私有化。下面示例中,_name被私有化,而age仍是公开的:

void test() { Dog d = new Dog('哈巴狗', 5); // 这个报错:_name 是私有变量,外部无法访问 // print(d.name); print(d.age); } class Dog { String _name; int age; Dog(this._name, this.age); String get respectedName { return 'Mr.$_name'; } set respectedName(String newName) { _name = newName; } Dog.newBorn() { _name = '哈巴狗'; age = 0; } bark() { print('Bow Wow'); } _hiddenMethod() { print('I can only be called internally!'); } }

调用私有化变量或方法时,IDE 会给出红色警告/报错提示。特别注意:Dart 的_私有性是"库级别(library-level)"的,而非"类级别"——即同一个.dart文件(同一库)内的其他类依然可以访问,只有跨文件(跨库)访问才会被禁止。这与 Java 的 private 语义有明显区别。

6.2 getter / setter 封装

上例同时展示了 Dart 的 getter/setter 语法:get respectedName与set respectedName。这允许我们在外部以属性访问的方式(d.respectedName)读写私有字段,同时内部可以加入格式化、校验等逻辑。如上例中 getter 返回'Mr.$_name',实现了对_name的受控访问。结合 flutter/01.Dart基础/01.Dart基础类型介绍.md 1.2 节的说明:普通变量自带 getter/setter,而final/const变量只有 getter。

6.3 Flutter 中的命名约定

Flutter 官方示例中,私有 State 类普遍命名为_MyHomePageState(见 flutter/02.基础知识/00.Flutter案例介绍.md 3.4 节),_counter等私有状态变量也以_开头。这种"下划线即私有"的约定,是 Dart 团队在语言层面刻意保留的极简设计。

07. 静态方法与静态属性:static 关键字

如果想让方法或属性静态化(不依赖实例,通过类名直接访问),只需在声明前添加static关键字:

void test() { Dog.bark(); } class Dog { static bark() { print('Bow Wow'); } }

静态成员的使用注意:

  • 通过类名.成员直接调用,无需创建实例;
  • 静态方法中不能访问实例成员(this不可用),只能访问其他静态成员;
  • 静态属性常用于定义常量与全局配置。仓库 flutter/01.Dart基础/01.Dart基础类型介绍.md 1.2.2 节展示了组合用法:
// static const 组合代表了静态常量 static const String complete = "COMPLETE";

其中const是编译期常量(值在编译期确定),final是运行期常量(第一次使用时初始化);const 变量同时也是 final 变量,实例变量可以为 final 但不能是 const(见 1.2.3 节注意事项)。

在 Flutter 中,Theme.of(context)、Navigator.push(...)等大量 API 都是静态方法/静态属性,理解static有助于快速定位框架入口。

08. 泛型:让类持有任意类型的数据

Dart 全面支持泛型(Generic)。当你希望类能持有任意类型的数据、同时又想在编译期保留类型信息时,可以为类声明泛型参数<T>:

DataHolder<String> dataHolder = new DataHolder('Some data'); print(dataHolder.getData()); dataHolder.setData('New Data'); print(dataHolder.getData()); // 下面这个会报错,因为 dataHolder 对象在创建的时候就已经限制为 String 类型 // dataHolder.setData(123); print(dataHolder.getData()); class DataHolder<T> { T data; DataHolder(this.data); getData() { return data; } setData(data) { this.data = data; } }

8.1 泛型的核心价值

  • 编译期类型检查:DataHolder<String>一旦创建,setData(123)会在编译期直接报错,把运行时错误前置到编译期;
  • 消除强制类型转换:getData()直接返回T类型,无需向下转型;
  • 可复用性:一个DataHolder<T>可以服务于任何数据类型,业务侧只需在实例化时指定具体类型。

8.2 集合与泛型

仓库 flutter/01.Dart基础/01.Dart基础类型介绍.md 2.3/2.4 节展示了泛型在集合中的标准用法:List<String>表示元素类型确定的列表,Map<String, Object>表示键值对类型确定的映射。定义List用[]、定义Map用{},二者都可以结合泛型限定元素类型。

8.3 泛型、dynamic 与 Object 的取舍

泛型不是唯一的选择,Dart 还提供dynamic与Object两种"宽松类型"。三者的差异(详见 flutter/01.Dart基础/01.Dart基础类型介绍.md 1.3 节):

  • dynamic:声明的变量可以赋值任意对象,且编译器提供所有可能的成员组合(类似 Objective-C 的id),但这容易引入运行时错误,需格外谨慎;
  • Object:声明的变量可以赋值任意对象,但只能使用Object自身的属性与方法,否则编译器报错(例如Object b; b.length会报 "The getter 'length' is not defined for the class 'Object'");
  • 泛型<T>:类型在实例化时确定,既能赋值具体类型数据,又能获得完整的编译期类型检查与智能提示。

实践中建议优先使用泛型限定具体类型,次选Object,dynamic仅在与原生平台交互(如 MethodChannel 动态数据)等确实无法确定类型的场景使用。

09. 面向对象实战:与 Flutter 开发结合

Dart 面向对象不仅是语法知识,更是 Flutter 开发的底层语言基础。结合仓库内容总结几条实战关联:

  1. Widget 即类,页面即实例化:void main() => runApp(new MyApp());(flutter/02.基础知识/00.Flutter案例介绍.md 3.2 节)中MyApp就是StatelessWidget的子类实例,runApp的源码WidgetsFlutterBinding.ensureInitialized()..attachRootWidget(app)..scheduleWarmUpFrame()正是"创建根 Widget 对象并挂载"的过程;
  2. 有状态与无状态之分:StatelessWidget用于不需要维护状态的场景,StatefulWidget通过关联一个State对象保存可变状态(flutter/03.原理分析/03.Widget原理详细分析.md 2/3 节),这背后是"不可变 Widget + 可变 State"的面向对象设计;
  3. 抽象类定义框架契约:Widget抽象类只声明createElement(),具体渲染交给各子类,理解这一点才能读懂整个 Flutter 框架;
  4. 构造与重定向优化代码:业务实体类可借鉴Dog.newBorn(Map json)模式,从Map/JSON 构建模型;子类构造统一经this(...)重定向到主构造函数,避免重复初始化;
  5. 枚举与元数据补充:Dart 支持enum(用法与 Java 相同),元数据注解以@开头(如@override、@deprecated),还可以自定义注解类(如const toDo(this.who, this.what)),详见 flutter/01.Dart基础/01.Dart基础类型介绍.md 6.1/6.3 节;
  6. 实战注意点:字符串拼接推荐使用$/${}而非+(+拼接 null 会抛_StringBase.+异常);异步回调中先判断mounted再调用setState,避免setState() called after dispose()(详见 flutter/01.Dart基础/05.Dart实践注意事项.md 1.1/1.3 节)。

附:本系列延伸阅读

  • flutter/01.Dart基础/01.Dart基础类型介绍.md:var/final/const、dynamic 与 Object、List/Map、函数与流程控制、枚举与元数据;
  • flutter/01.Dart基础/05.Dart实践注意事项.md:字符串拼接、空安全判断、setState 生命周期陷阱;
  • flutter/02.基础知识/00.Flutter案例介绍.md:runApp 入口、StatefulWidget/StatelessWidget 的实际用法;
  • flutter/03.原理分析/03.Widget原理详细分析.md:Widget 抽象类源码、继承链与 Element 对应关系。
  • 教程
  • 技术博客
  • 文档

【免费下载链接】YCBlogs

技术博客笔记大汇总,包括Java基础,线程,并发,数据结构;Android技术博客等等;常用设计模式;常见的算法;网络协议知识点;部分flutter笔记;还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!转载请注明出处,谢谢!

项目地址:https://gitcode.com/gh_mirrors/yc/YCBlogs
点击查看免费下载
上一篇:鼠标悬停翻译神器MouseTooltipTranslator:一键跨越语言障碍的终极解决方案
下一篇:Firefox Translations 项目教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 20:35:37

windows下mysql中binlog日志分析和数据恢复

1.首先查看是否开启了binlog show variables like %log_bin%;看到了是没有开启的。 2.开启binlog日志&#xff0c;并重启mysql服务 不能通过命令的方式去打开&#xff0c;因为会提示说这个参数是只读的。如下图&#xff1a;所以&#xff0c;打开mysql的配置文件&#xff0c;找到…

作者头像 李华
网站建设 2026/10/15 1:27:33

PCA9422+MK60DN512VLQ10低功耗电源管理方案设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 15:25:46

基于YOLOv5的直肠息肉检测:完整程序、数据集与RK3568量化部署实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 9:22:17

最大熵模型预测实战:从原理到栅格生成的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华