Flutter/Dart第14天:Dart类详解

伤心客  金牌会员 | 2023-11-12 17:53:28 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 906|帖子 906|积分 2718

Dart官方文档:https://dart.dev/language/classes
重要说明:本博客基于Dart官网文档,但并不是简单的对官网进行翻译,在覆盖核心功能情况下,我会根据个人研发经验,加入自己的一些扩展问题和场景验证。
Dart类

Dart语言基于Mixin继承,是一门面向对象语言。任何对象都是某个类的实例,除Null之外,Object类其他所有类的父类。
Mixin继承:Dart语言和Java语言一样,类只能是单继承。但通过Mixin,一个类的代码可以在多个类层次结构中复用(有关Minxin的详细说明见之前文章:https://ntopic.cn/p/2023093001)。
方法扩展:在不改变原有类和增加子类的情况之下,通过Dart的方法扩展,可以给类增加功能的一种方法(这个特性在Flutter发布的库特别有用)。
类修饰符:可以让我们可控制一个库如果定义子类。
类成员(方法和变量)

对象是由函数和数据组成,分别代码方法和变量。我们通过对象.方法或者对象.变量的方法来访问对象方法和变量。当对象可能为null时,通过对象.?访问方法和变量的方式可防止异常发生。
  1. // 定义对象
  2. var p = Point(2, 2);
  3. // 获取对象变量`y`
  4. assert(p.y == 2);
  5. // 调用对象方法:`distanceTo()`
  6. double distance = p.distanceTo(Point(4, 4));
  7. // 当对象`p`非空时,`a`值为变量`y`;否则`a`值为null
  8. var a = p?.y;
复制代码
类构造函数

在前面学习中,我们对构造函数有初步认识:https://ntopic.cn/p/2023092401
如下代码样例,可以通过主构造函数和命名构造函数创建一个对象;构造函数之前,我们也可以增加可选的new关键字:
  1. var p1 = Point(2, 2);
  2. var p2 = Point.fromJson({'x': 1, 'y': 2});
  3. // 同上等价代码,可选的`new`关键字
  4. var p1 = new Point(2, 2);
  5. var p2 = new Point.fromJson({'x': 1, 'y': 2});
复制代码
当类的变量都用final不可变修饰时,我们可以构造常量对象:
  1. var a = const ImmutablePoint(1, 1);
  2. var b = const ImmutablePoint(1, 1);
  3. // 对象`a`和`b`相等
  4. assert(identical(a, b));
复制代码
对于一个常量上下文,我们可以去掉构造函数之前的const关键字。如下代码样例,我们定义的是一个常量Map(上下文),那么Map元素的构造器就可以省略const关键字:
  1. const pointAndLine = const {
  2.   'point': const [const ImmutablePoint(0, 0)],
  3.   'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
  4. };
  5. // 同上等价代码,可省略`const`关键字
  6. const pointAndLine = {
  7.   'point': [ImmutablePoint(0, 0)],
  8.   'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
  9. };
复制代码
如果一个对象没有常量上下文,且没有使用const修饰构造器,那么它创建的是一个非常量对象:
  1. var a = const ImmutablePoint(1, 1);
  2. var b = ImmutablePoint(1, 1);
  3. // `a`是常量对象,`b`不是常量对象,因此它们不相等!
  4. assert(!identical(a, b));
复制代码
获取对象类型

通过对象.runtimeType属性,返回对象的Type对象。一般情况下,我们通过对象 is Type的方法,检测某个对象是否属于某个类型,而不是使用对象.runtimeType == Type比较方式:
  1. print('The type of a is ${a.runtimeType}');
  2. var a = 'Hello NTopicCN';
  3. assert(a.runtimeType == String);
  4. assert(a is String);
复制代码
实例变量

如下代码定义样例,申明实例变量,实例变量的默认值为null:
  1. class Point {
  2.   double? x; // 默认值:null
  3.   double? y; // 默认值:null
  4.   double z = 0; // 默认值:0
  5. }
复制代码
所有的实例变量都隐含有一个getter方法,包括final修饰的变量未使用final修饰的变量late final修饰的变量(赋值和未赋值)等,都有getter方法。
如下代码样例,几种实例变量修饰和访问的方法:
  1. class Point {
  2.   double? x;
  3.   double? y;
  4. }
  5. void main() {
  6.   var point = Point();
  7.   point.x = 4; // `setter`方法赋值
  8.   assert(point.x == 4); // `getter`方法取值
  9.   assert(point.y == null); // 默认值为`null`
  10. }
  11. class ProfileMark {
  12.   final String name;
  13.   final DateTime start = DateTime.now();
  14.   // 主构造函数
  15.   ProfileMark(this.name);
  16.   // 命名构造函数,同时`name`设置初始值
  17.   ProfileMark.unnamed() : name = '';
  18. }
复制代码
隐性接口

在Dart中,每个类都隐含的定义了一个接口,这个接口包含了该类的所有实例成员和该类实现的所有的其他接口。
假设我们定义了一个类A,它需要支持类B的API(构造函数不是API),但是类A的定义并不是继承类B,那么类A需要实现B接口。
  1. // `Person`类,也是`Persion`接口,包含`greet()`方法
  2. class Person {
  3.   // 属于接口的一部分,但是对外不可见
  4.   final String _name;
  5.   // 构造函数,不属于接口一部分
  6.   Person(this._name);
  7.   // 普通方法,属于接口一部分
  8.   String greet(String who) => 'Hello, $who. I am $_name.';
  9. }
  10. // 实现`Person`接口
  11. class Impostor implements Person {
  12.   String get _name => '';
  13.   String greet(String who) => 'Hi $who. Do you know who I am?';
  14. }
  15. String greetBob(Person person) => person.greet('Bob');
  16. void main() {
  17.   print(greetBob(Person('Kathy'))); // Hello, Bob. I am Kathy.
  18.   print(greetBob(Impostor())); // Hi Bob. Do you know who I am?
  19. }
复制代码
类变量和方法

static关键字,可以定义类变量和方法(Java中成为静态变量和静态方法)。
如下代码样例,定义和使用一个类变量:
  1. class Queue {
  2.   static const initialCapacity = 16;
  3.   // ···
  4. }
  5. void main() {
  6.   assert(Queue.initialCapacity == 16);
  7. }
复制代码
如下代码样例,定义和使用类方法:
  1. import 'dart:math';
  2. class Point {
  3.   double x, y;
  4.   Point(this.x, this.y);
  5.   static double distanceBetween(Point a, Point b) {
  6.     var dx = a.x - b.x;
  7.     var dy = a.y - b.y;
  8.     return sqrt(dx * dx + dy * dy);
  9.   }
  10. }
  11. void main() {
  12.   var a = Point(2, 2);
  13.   var b = Point(4, 4);
  14.   var distance = Point.distanceBetween(a, b);
  15.   assert(2.8 < distance && distance < 2.9);
  16.   print(distance);
  17. }
复制代码
最佳实践:对于一些常用的工具方法,建议使用顶级方法代替类变量。
类方法可以用作编译期常量,比如:我们可以把一个类方法当作参数传递给常量构造器。
我的本博客原地址:https://ntopic.cn/p/2023102001

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表