「 Dart 」Dart 中的类

62 篇文章 1 订阅
19 篇文章 1 订阅

在 Dart 中所有对象都是某个类的实例,所有类继承了 Object 类。

构造函数

import 'dart:math';

// 定义类
class Point {
  num x = 0, y = 0;

  // Point(this.x, this.y); // 构造器

  // 或者
  Point(x, y) {
    this.x = x;
    this.y = y;
    print('这是构造函数,在实例化时触发');
  }

  // 实例方法
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

main() {
  // 调用类的构造函数,new 可以省略
  Point p1 = new Point(1, 2); // 这是构造函数,在实例化时触发
  Point p2 = Point(3, 4); // 这是构造函数,在实例化时触发
  // 调用类方法
  print(p1.distanceTo(p2)); // 2.8284271247461903
} 

由于 Dart 2.12 的特性,这样写构造函数会报错:

class Point {
  num x, y;
  Point(x, y) {  // 不可为空的实例字段 'x' 必须被初始化
      			// 尝试添加一个初始化表达式,或者在这个构造函数中添加一个字段初始化器,或者标记它
    this.x = x;
    this.y = y;
  }
} 

由于空安全,Dart 不知道你是否为 x,y 分配了变量。该写法在之前的版本没有问题,解决方法是dart - Non-nullable instance field must be initialized - Stack Overflow

解决方法之一:

class Point {
  num? x, y;
  Point(x, y) {
    this.x = x;
    this.y = y;
  }
} 

num?表示可空类型,表示变量值可以为空。

使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数使代码语义化,之前使用的 DateTime.now() 也是命名构造函数。

使用重定向构造函数,用冒号调用其他构造函数。

class Point {
  num? x;
  num? y;

  Point.initX(y) { // 命名构造函数
    this.x = 2;
    this.y = y;
  }

  Point.redirctor(num x) : this(x, 0); // 重定向构造函数
}

main() {
  Point p1 = Point.initX(2); 
  print('${p1.x}, ${p1.y}'); // 2, 2
  Point p2 = Point.redirctor(1); 
  print('${p2.x}, ${p2.y}'); // 1, 0
} 

代码越来越多导致维护性越来越差,所以我们需要把类抽离成文件,在需要的地方使用import导入库。

// lib\Point.dart
class Point {
  num x = 0, y = 0;
  Point(this.x, this.y); 
}

// main.dart
import 'lib/Point.dart';
main(){
	//...
} 

类及成员可见性

Dart 中的可见性以 library 为单位,每个Dart 文件就是一个库。

使用_表示属性或方法的私有属性,相当于 Java 中的privite

class Point {
  num _x = 0, _y = 0;
  Point(this.x, this.y); 
} 

当其被抽离成一个文件时,私有属性的作用才生效。

getter,setter

每个变量都有其默认的gettersetter方法,final 声明的变量只可读,只有 getter 方法。

在 Dart 中,方法不能重载。

class Rect {
  late num width, height;
  Rect(this.width, this.height);
  area() {
    return this.width * this.height;
  }

  // getter
  get area1 {
    return this.width * this.height;
  }

  // setter
  set height2(value) {
    this.height = value;
  }
}

main() {
  Rect r1 = Rect(1, 2);
  print(r1.area()); // 2
  print(r1.area1); // 2
  r1.height2 = 3;
  print(r1.area1); // 3
} 

初始化列表

初始化列表是在实例化之前进行的操作:

class Rect {
  late num width, height;
  // Rect(this.width, this.height); 不能同时使用
  Rect()
      : width = 2,
        height = 3 {
    print('in class');
    print(this.width * this.height);
  }
}

main() {
  Rect r1 = Rect();
  print('in main');
}

// 输出结果
// in class
// in main
// 6 

static 静态成员

静态变量和静态方法可以通过类来访问,而不是类的实例。

class Person {
  static String name = 'Jackie';
  static void show() {
    print(name);
  }
}

main() {
  print(Person.name); //Jackie
  Person.show(); // Jackie
} 

静态的方法不可以访问非静态的成员,非静态的方法可以访问静态的成员。

class Person {
  static String name = 'Jackie';
  static show() {
    print(name);
  }
  showInfo() {
    print(name);
    show();
  }
}

main() {
  Person p = Person();
  p.showInfo(); // Jackie Jackie
} 

继承

  1. 子类使用extends关键词来继承父类;

  2. 子类会继承父类里除构造函数的可见的属性和方法;

  3. 子类能复写父类的方法。

class Person {
  late String name;
  late int age;
  Person(this.name, this.age);
  work() {
    print('$name is working.');
  }
}

class Web extends Person {
  late String sex;
  // 子类的构造函数
  Web(String name, int age, String sex) : super(name, age) {
    this.sex = sex;
  }
  // 子类可以复写父类的方法
  @override // 表示覆写父类的方法,选写
  work() {
    print('$name is working 996.');
  }
}

main() {
  Web w = Web('Tom', 20, 'male');
  print(w.sex); // male
  w.work(); // Tom is working 996.
} 

抽象类

Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。

  1. 抽象类通过 abstract 关键字来定义。
  2. Dart 中没有方法体的方法称为抽象方法。
  3. 如果子类继承抽象类必须要实现里面的抽象方法。
  4. 如果把抽象类当做接口实现的话必须要实现抽象类里面定义的所有属性和方法。
  5. 抽象类不能被实例化,只有继承它的子类可以。

extends 抽象类和 implements 的区别:

  1. 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类。
  2. 如果只是把抽象类当做标准的话就用 implements 实现抽象类。
abstract class Person {
  late String name;
  late int age;
  Person(this.name, this.age);
  work(); // 抽象方法
}

class Employee extends Person {
  Employee(String name, int age) : super(name, age);
  @override
  work() {
    print('$name is working 996.');
  }
}

class Employee2 extends Person {
  Employee2(String name, int age) : super(name, age);
  @override
  work() {
    print('$name is working 669.');
  }
}

main() {
  Person e = Employee('Tom', 20);
  e.work(); // Tom is working 996.
  // Person p = Person(); //报错,抽象类不能实例化
  Person e2 = Employee2('Jerry', 20);
  e2.work(); // Jerry is working 669.
} 

多态

是子类的实例赋值给父类的引用,允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。

多态就是父类定义一个方法,让继承他的子类去实现,每个子类有不同的表现。

上述例子中,Employee 和 Employee2 类都实现了多态。

接口

Dart 也有接口,但是和 Java 有区别。

Dart 的接口没有 interface 关键字,而是普通类或抽象类都可以作为接口使用 implements 关键字被实现。

如果实现的类是普通类,会将普通类和抽象类中的属性的方法全部需要覆写一遍.而因为抽象类可以定义抽象方法,普通类不可以,所以建议使用抽象类定义接口。

abstract class Db {
  late String uri;
  add(String data);
}

class Mysql implements Db {
  @override
  late String uri;

  Mysql(this.uri);

  @override
  add(String data) {
    print('This is Mysql. ' + '$data');
  }
}

main() {
  Mysql m = Mysql('xxx');
  m.add('123');
} 

接口抽离成不同的文件:

// lib\Db.dart
abstract class Db {...}

// lib\Mysql.dart
import 'lib/Db.dart';
class Mysql implements Db {...}

// main.dart
import 'lib/Mysql.dart';
main() {...} 

一个类可以实现多个接口

class C implements A, B {
    // A, B 接口所有的属性和方法
} 

Mixins

Class 中无法实现多继承,Mixins 不同于继承和接口,可以实现类似多继承的功能:

class C extends A, B {} // 报错
class C with A, B {...} // √ 
  1. 作为 Mixins 的类只能继承自Object,不能继承其他类。
  2. 作为 Mixins 的类不能有构造函数。
  3. 一个类可以 Mixins 多个 Mixins 类。
  4. Mixins 绝不是继承,也不是接口,而是一种全新的特性。
class A {...}
class B extends A {...}
class C {...}
class D with B, c {...} // 报错
class D extends A with B, C {...} // √ 

后写的类会覆盖掉前面的类:

class C with A, B {...} // B 的方法会覆盖掉 A
class D extends A with B, C {...} // B 的方法会覆盖掉 A,C 的方法会覆盖掉 A 和 B 

最后

有小伙伴私信问Compose的问题,好不好用啊,现在要不要学啊?

其实答案很简单,自从谷歌2019年公布了声明式UI框架Jetpack Compose后,两年多的时间,各种大力宣传,和大量资源的倾斜,API功能都趋于稳定了。

至于好不好用,各种用过的同行都是持肯定态度的。优势大概就是这四点:

强大的工具和直观的Kotlin API
简化并加速了Android上的UI开发
可以帮助开发者用更少更直观的代码创建View
有更强大的功能,以及还能提高开发速度

这么大的优势,毋庸置疑,肯定是要学的嘛,而且越快掌握越好。别等刀架到脖子上了,才去练金钟罩。

至于怎么快速上手,可以给大家免费分享一份**《Jetpack Compose 完全开发手册》**,手把手教大家从入门到精通。

第一章 初识 Jetpack Compose

  • 为什么我们需要一个新的UI 工具?

  • Jetpack Compose的着重点

    加速开发
    强大的UI工具
    直观的Kotlin API

图片

  • API 设计

图片

  • Compose API 的原则
    一切都是函数
    顶层函数(Top-level function)
    组合优于继承
    信任单一来源

图片

  • 深入了解Compose
    Core
    Foundation
    Material

图片

  • 插槽API

第二章 Jetpack Compose构建Android UI

  • Android Jetpack Compose 最全上手指南
    Jetpack Compose 环境准备和Hello World
    布局
    使用Material design 设计
    Compose 布局实时预览
    ……

图片

  • 深入详解 Jetpack Compose | 优化 UI 构建
    Compose 所解决的问题
    Composable 函数剖析
    声明式 UI
    组合 vs 继承
    封装
    重组
    ……

图片

  • 深入详解 Jetpack Compose | 实现原理
    @Composable 注解意味着什么?
    执行模式
    Positional Memoization (位置记忆化)
    存储参数
    重组
    ……

图片

第三章 Jetpack Compose 项目实战演练(附Demo)

  • Jetpack Compose应用1
    开始前的准备
    创建DEMO
    遇到的问题

图片

  • Jetpack Compose应用2
  • Jetpack Compose应用做一个倒计时器
    数据结构
    倒计时功能
    状态模式
    Compose 布局
    绘制时钟

图片

  • 用Jetpack Compose写一个玩安卓App
    准备工作
    引入依赖
    新建 Activity
    创建 Compose
    PlayTheme
    画页面
    底部导航栏
    管理状态
    添加页面

图片

  • 用Compose Android 写一个天气应用
    开篇
    画页面
    画背景
    画内容
    ……

图片

  • 用Compose快速打造一个“电影App”
    成品
    实现方案
    实战
    不足
    ……

图片

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
有需要的话可以点下面二维码免费领取↓↓↓

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值