Dart 面试题整理
一、基础概念题
- Dart 语言特点
问:Dart 有哪些主要特点?
· 面向对象,支持 mixin 继承
· 可选类型系统和强类型(支持 sound null safety)
· 支持 async/await 异步编程
· JIT(Just-In-Time)和 AOT(Ahead-Of-Time)编译
· isolates 实现并发(非线程)
· 支持泛型
· 树摇(tree shaking)优化
- 空安全
问:Dart 的空安全是什么?如何声明可空类型?
dart
// 非空类型
String name = 'Dart';
// 可空类型
String? nullableName;
// 必要参数
void printName(String name) {}
// 可选参数
void printName(String? name) {}
// 使用 ! 断言非空(谨慎使用)
String result = nullableName!;
- const 与 final
问:const 和 final 有什么区别?
dart
// final: 运行时常量,只能赋值一次
final now = DateTime.now();
// const: 编译时常量,必须是编译时能确定的值
const pi = 3.14;
const list = [1, 2, 3];
// const 构造函数创建编译时常量
class Point {
final int x, y;
const Point(this.x, this.y);
}
const point = Point(1, 2);
二、核心语法题
- 异步编程
问:Future 和 Stream 的区别?如何使用 async/await?
dart
// Future: 表示一个异步操作的结果
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 1));
return 'Data loaded';
}
// Stream: 表示一系列异步事件
Stream<int> countStream(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(Duration(milliseconds: 100));
yield i;
}
}
// 使用
void main() async {
var data = await fetchData();
print(data);
await for (var value in countStream(5)) {
print(value);
}
}
- 集合操作
问:Dart 有哪些集合类型?解释 List、Set、Map 的区别
dart
// List: 有序集合,可重复
List<int> numbers = [1, 2, 3, 3];
numbers.add(4);
// Set: 无序集合,不可重复
Set<int> uniqueNumbers = {1, 2, 3, 3}; // {1, 2, 3}
// Map: 键值对集合
Map<String, int> scores = {'Alice': 90, 'Bob': 85};
// 集合操作
var doubled = numbers.map((n) => n * 2).toList();
var evens = numbers.where((n) => n % 2 == 0).toList();
- 扩展方法
问:什么是扩展方法?如何创建?
dart
// 为 String 添加扩展方法
extension StringExtension on String {
bool get isPalindrome {
return this == reversed;
}
String get reversed {
return split('').reversed.join('');
}
}
// 使用
void main() {
print('racecar'.isPalindrome); // true
print('hello'.reversed); // olleh
}
三、面向对象编程
- 继承与混入
问:Dart 如何实现多重继承?解释 mixin 的用法
dart
// 普通类
class Animal {
void eat() => print('Eating');
}
// Mixin 使用 mixin 关键字(不能有构造函数)
mixin Flyable {
void fly() => print('Flying');
}
mixin Swimmable {
void swim() => print('Swimming');
}
// 继承 + 混入
class Bird extends Animal with Flyable {}
class Duck extends Animal with Flyable, Swimmable {}
void main() {
var duck = Duck();
duck.eat(); // Eating
duck.fly(); // Flying
duck.swim(); // Swimming
}
- 工厂构造函数
问:工厂构造函数有什么特点?
dart
class Logger {
final String name;
static final Map<String, Logger> _cache = <String, Logger>{};
// 工厂构造函数,可以返回缓存实例
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// 私有命名构造函数
Logger._internal(this.name);
void log(String msg) {
print('$name: $msg');
}
}
// 使用
void main() {
var logger1 = Logger('app');
var logger2 = Logger('app'); // 相同的实例
print(identical(logger1, logger2)); // true
}
- 泛型
问:解释泛型在 Dart 中的应用
dart
// 泛型类
class Box<T> {
T value;
Box(this.value);
T getValue() => value;
}
// 泛型方法
T first<T>(List<T> items) {
return items.first;
}
// 泛型约束
class NumberBox<T extends num> {
T value;
NumberBox(this.value);
}
void main() {
var box = Box<int>(42);
print(box.getValue());
var numbers = NumberBox<double>(3.14);
}
四、高级特性
- Isolate
问:Dart 如何处理并发?Isolate 与线程的区别?
dart
// Isolate 示例
import 'dart:isolate';
void isolateFunction(SendPort sendPort) {
sendPort.send('Hello from isolate!');
}
void main() async {
var receivePort = ReceivePort();
await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
receivePort.listen((message) {
print('Received: $message');
receivePort.close();
});
}
关键区别:
· Isolate 有独立内存,通过消息传递通信
· 线程共享内存,需要锁机制
· Isolate 更安全,避免了竞态条件
- 元数据注解
问:Dart 中的注解如何工作?
dart
// 自定义注解
class Todo {
final String todo;
const Todo(this.todo);
}
// 使用注解
@Todo('Implement this method')
void calculate() {
// TODO: 实现这个方法
}
// 内置注解
@deprecated
void oldMethod() {}
@override
String toString() => 'Custom object';
五、Flutter 相关
- Widget 生命周期
问:StatefulWidget 的生命周期方法有哪些?
dart
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
// 1. 初始化
@override
void initState() {
super.initState();
print('initState');
}
// 2. 依赖变化
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies');
}
// 3. 重建
@override
void didUpdateWidget(MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}
// 4. 构建
@override
Widget build(BuildContext context) {
return Container();
}
// 5. 销毁
@override
void dispose() {
print('dispose');
super.dispose();
}
}
- BuildContext
问:BuildContext 是什么?在什么情况下会用到?
· 组件在树中的位置引用
· 用于查找 InheritedWidget
· 导航、主题、媒体查询等都需要 context
dart
// 获取主题
Theme.of(context).primaryColor;
// 导航
Navigator.of(context).push(...);
// 媒体查询
MediaQuery.of(context).size;
六、实战编程题
- 错误处理
问:编写一个安全的异步数据加载函数
dart
Future<Result<T>> safeLoadData<T>(
Future<T> Function() loader,
) async {
try {
final data = await loader();
return Result.success(data);
} on SocketException catch (e) {
return Result.failure('网络连接失败: ${e.message}');
} on HttpException catch (e) {
return Result.failure('HTTP错误: ${e.message}');
} on FormatException catch (e) {
return Result.failure('数据格式错误: ${e.message}');
} catch (e) {
return Result.failure('未知错误: $e');
}
}
class Result<T> {
final T? data;
final String? error;
final bool isSuccess;
Result.success(this.data)
: error = null,
isSuccess = true;
Result.failure(this.error)
: data = null,
isSuccess = false;
}
- 状态管理
问:实现一个简单的状态管理
dart
import 'package:flutter/material.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void decrement() {
_count--;
notifyListeners();
}
}
// 使用 Provider 消费
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<CounterModel>();
return Text('Count: ${counter.count}');
}
}
七、性能优化
-
如何优化 Dart/Flutter 应用性能?
-
避免不必要的重建
· 使用 const 构造函数
· 合理使用 const Widget
· 使用 shouldRebuild
-
列表优化
· 使用 ListView.builder
· 添加 itemExtent
· 使用 AutomaticKeepAliveClientMixin
-
图片优化
· 使用合适分辨率的图片
· 实现图片缓存
· 使用 loadingBuilder
-
减少布局计算
· 避免多层嵌套
· 使用 SizedBox 替代 Container
· 使用 Align 和 Positioned
八、常见问题解答
- Dart 与 JavaScript/TypeScript 的主要区别?
· Dart 是编译型语言,JavaScript 是解释型
· Dart 有更好的类型系统(sound null safety)
· Dart 内置 async/await 支持更好
· Dart 有 isolates,JavaScript 有 Worker
- 什么时候使用 async* 和 yield?
dart
// async* 用于生成 Stream
Stream<int> countDown(int from) async* {
for (int i = from; i >= 0; i--) {
await Future.delayed(Duration(seconds: 1));
yield i; // 生成 Stream 值
}
}
// 对比普通 async
Future<int> calculate() async {
await Future.delayed(Duration(seconds: 1));
return 42; // 返回单个 Future 值
}
- Dart 中的级联运算符(...)有什么用途?
dart
var button = Button()
..text = 'Submit'
..color = Colors.blue
..onPressed = () => print('Pressed')
..padding = EdgeInsets.all(8);
// 等同于:
var button = Button();
button.text = 'Submit';
button.color = Colors.blue;
// ...
九、面试准备建议
- 理解核心概念:空安全、异步编程、Stream
- 掌握 Flutter 架构:Widget、Element、RenderObject
- 熟悉状态管理:Provider、Riverpod、Bloc
- 了解性能优化:渲染原理、内存管理
- 实践项目经验:准备项目案例,能解释技术选型
- 编码规范:熟悉 Effective Dart 指南
- 调试技能:知道如何使用 Dart DevTools
这份 Dart 面试题整理涵盖了从基础到高级的各个方面,建议结合实际编码练习来巩固理解。在面试前,重点关注你实际项目中用到的技术和遇到的挑战,准备好具体的案例分析。