Dart语言——45分钟快速入门(下)
类和对象
类的定义
// Dart中定义一个类
class Person {String name;int age;Person(String name, int age) {this.name = name;this.age = age;}
}
复制代码
Dart中的类与Java中的相似,不同的是,Dart中没有private
、public
这些成员访问修饰符。如果是类私有的成员,不希望外面访问,只需要在成员变量之前加上一个下划线_
变为私有即可。
以上代码,在Dart中还有一种简化写法,可以自动在构造方法中对成员变量初始化。
// Dart中定义一个类
class Person {String name;int age;// 在构造方法中初始化成员变量时,可使用如下写法简化Person(this.name, this.age);// 如需处理其他变量时,也可单独对其操作// Person(this.name, this.age, String address){// print(address);// }// 注意,构造方法不能重载,以上注释掉
}
复制代码
另外还需要注意一点,Dart中没有构造方法的重载,不能写两个同名的构造方法。
Getters 和 Setters方法
在Java中,一般不会直接在类的外部去访问类成员,通常使用setter和getter方法来操作类的成员变量。而在Dart语言中,所有类中都包含隐式的getter方法,对于非final
修饰的成员,类中还包含隐式的setter方法。这就意味着,在Dart中,你可以直接在类外部通过.
操作符访问类成员。这一特点使得Dart语法更加简洁,不会写出满屏的setXXX、getXXX方法。
当然,很多时候我们调用setter和getter方法并不仅仅是为了赋值和访问,而是为了一些额外的处理,这时候我们只需要使用set
与get
关键字实现setter和getter方法即可。
class Person {String userName;Person(this.userName);// 方法名前加get关键字String get name{return "user:" + this.userName;}// 方法名前加set关键字set name(String name){// do somethingthis.userName = name;}
}void main() {var p = new Person("zhangsan");print(p.name); // user:zhangsanp.name = "Jack";print(p.name); // user:Jack
}
复制代码
要注意,在创建对象时,new
关键字并不是必须的,可以省略不写。在写Flutter界面时,不建议写new
关键字实例化对象,因为Flutter框架中没有类似的xml语言来描述UI界面,界面也是使用Dart语言来写,在使用Dart写UI时,要保持代码的简洁和结构化,省略new
会更友好。
构造方法
如果没有定义构造方法,则会有一个默认的无参构造方法,并且会调用超类的无参构造方法。
命名构造方法
上面已经说过,Dart类中两个同名构造方法不能重载,但是Dart语言为类新增了一种称为命名构造方法
的东西。
class Person {String userName;int age;Person(this.userName, this.age);// 命名构造方法Person.fromData(Map data) {this.userName = data['name'];this.age = data['age'];}
}void main() {// 使用命名构造方法创建对象var p = new Person.fromData({"name":"Bob","age":19});print(p.userName);
}
复制代码
注意,使用命名构造方法可以为一个类实现多个构造方法,也可以更清晰的表明意图。
常量构造方法
如果想提供一个状态永远不变的对像,在Dart中,我们可以创建一个编译时常量对象,节省开销。
class ConstPoint {final num x;final num y;// 使用const修构造方法const ConstPoint(this.x, this.y);// 编译时常量对象,需使用const来创建对象static final ConstPoint origin = const ConstPoint(0, 0);
}void main() {print(ConstPoint.origin.x);print(ConstPoint.origin.y);
}
复制代码
工厂构造方法
当我们需要创建一个新的对象或者从缓存中取一个对象时,工厂构造方法就派上了用场。
class Logger {final String name;// 创建一个静态Map做为缓存static final Map<String, Logger> _cache = <String, Logger>{};// 定义一个命名构造方法,用下划线"_"修饰,将构造方法私有化Logger._internal(this.name);// 使用关键字factory修饰类同名构造方法factory Logger(String name) {if (_cache.containsKey(name)) {return _cache[name];} else {// 调用命名构造方法创建新对象final logger= new Logger._internal(name);_cache[name] = logger; // 存入缓存return logger;}}
}void main() {var uiLog = new Logger('UI');var eventLog = new Logger('event');
}
复制代码
构造方法重定向
有时候一个构造方法会调动类中的其他构造方法来实例化,这时候可以使用构造方法重定向,
class Point {num x;num y;// 同名构造方法Point(this.x, this.y);// 命名构造方法重定向到同名构造方法,中间使用一个冒号Point.alongXAxis(num x) : this(x, 0);
}
复制代码
类的初始化列表
熟悉C++的朋友应该对初始化列表很了解了,Java中是没有这个特性的。
class Point {final num x;final num y;final num distance;Point(x, y): x = x,y = y,distance = sqrt(x * x + y * y){print("这是构造方法");}
}void main() {var p = new Point(2, 3);print(p.distance);
}
复制代码
- 初始化列表位于构造方法的小括号与大括号之间,在初始化列表之前需添加一个冒号。
- 初始化列表是由逗号分隔的一些赋值语句组成。
- 它适合用来初始化
final
修饰的变量 - 初始化列表的调用是在构造方法之前,也就是在类完成实例化之前,因此初始化列表中是不能访问
this
的
运算符重载
这个特性,又很类似于C++中的运算符重载,在Java中是没用这种概念的。
class Point {int x;int y;Point(this.x, this.y);// 使用operator关键字,为该类重载"+"运算符Point operator +(Point p) {return new Point(this.x + p.x, this.y + p.y);}// 为该类重载"-"运算符Point operator -(Point p) {return new Point(this.x - p.x, this.y - p.y);}
}void main(){var p1 = new Point(1,5);var p2 = new Point(7,10);// 重载运算符后,类可以使用“+”、“-” 运算符操作var p3 = p1 + p2;var p4 = p2 - p1;print("${p3.x}, ${p3.y}");print("${p4.x}, ${p4.y}");
}
复制代码
打印结果:
8, 15
6, 5
复制代码
Dart中允许重载的运算符如下:
+
|
–
|
*
|
~/
|
/
|
%
|
^
|
<
|
>
|
<=
|
>=
|
==
|
[]
|
[]=
|
&
|
~
|
<<
|
>>
|
| |
类的继承
Dart中的继承,与Java中相似,可以使用关键字extends
继承父类,使用关键字super
引用父类
class Father {myFunction(){// do something}
}class Son extends Father {@overridemyFunction(){super.myFunction();// do something}
}
复制代码
我们都知道,Java中的类仅支持单继承,而Dart中的类可以实现多继承。要实现多继承,需要使用with
关键字。
// 首先定义三个父类
class Father1 {a(){print("this is a func");}common(){print("common Father1");}
}class Father2 {b(){print("this is b func");}common(){print("common Father2");}
}class Father3 {c(){print("this is c func");}common(){print("common Father3");}
}//定义子类
class Son extends Father1 with Father2,Father3{}void main() {var obj = new Son();obj.common();obj.a();obj.b();obj.c();
}
复制代码
打印结果:
common Father3
this is a func
this is b func
this is c func
复制代码
要注意,以上继承写法中,也可以直接使用with
,等价于如下写法
class Son with Father1,Father2,Father3{}
复制代码
接口抽象
抽象类
Dart语言没有提供
interface
关键字来定义接口,但是Dart语言中保留了抽象类,同Java,使用abstract
关键字来修饰抽象类。而Dart中的抽象类,实际上就相当于Java中的接口。
abstract class Base {// 省略函数体即可定义抽象方法,不需加关键字func1();func2();
}
复制代码
注意,抽象类是不能被实例化的,子类继承抽象类时,必须实现全部抽象方法。
隐式接口
实际上在Dart中,每个类都隐式的定义了一个包含所有实例成员的接口, 并且该类实现了这个接口。
因此,如果我们想实现某个接口,但有又不想继承,则可以使用这种隐式接口机制。我们需要用到关键字implements
class People {void greet(){print("Hello");}
}class Student implements People{@overridevoid greet(){print("Hi,I'm Alice.");}
}greet(People p){p.greet();
}void main() {greet(new Student());
}
复制代码
泛型
Dart中也支持泛型,用法与Java中类似。
// 泛型
var names = new List<String>();
names.add("zhangsan")var maps = new Map<int, String>();
maps[1]="value";// 字面量写法
var infos = <String>['Seth', 'Kathy', 'Lars'];var pages = <String, String>{'index.html': 'Homepage','robots.txt': 'Hints for web robots'
};
复制代码
异常处理
如果关心具体异常,针对不同异常进行不同处理,可以使用try...on
处理异常,finally
是可选的,用于最后的处理。
try {// 使除数为0print(11~/0);} on IntegerDivisionByZeroException {print("除数为0");}on Exception{print("Exception");}finally {print("finally");}
复制代码
不关心具体异常,只想捕获,避免异常继续传递,则可以使用try...catch
处理
try {print(11~/0);} catch(e){// 打印报错信息print(e);}finally {print("finally");}
复制代码
如果想获取更多异常信息,可以使用两个参数的catch
,第二个参数是异常的调用栈信息
try {print(11~/0);} catch(e,s){print(s);}
复制代码
如果你既想针对不同异常进行不同处理,还想打印调用栈信息,那就将两种结合起来使用
try {print(11~/0);} on IntegerDivisionByZeroException catch(e,s){print(s);} on Exception catch(e,s){print(s);}
复制代码
库与导入
Dart使用import
语句用来导入一个库,后面跟一个字符串形式的Uri来指定表示要引用的库。
// 指定dart:前缀,表示导入标准库,如dart:io
import 'dart:math';// 也可以用相对路径或绝对路径来引用dart文件
import 'lib/student/student.dart';// 指定package:前缀,表示导入包管理系统中的库
import 'package:utils/utils.dart';
复制代码
导入库时,可以使用as
关键字来给库起别名,避免命名空间冲突。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;// 使用lib1中的Element
Element element1 = new Element();
// 使用lib2中的Element
lib2.Element element2 = new lib2.Element();
复制代码
使用show
和hide
关键字控制库中成员的可见性
// 仅导入foo,屏蔽库中其他成员
import 'package:lib1/lib1.dart' show foo;// 屏蔽foo,库中其他成员都可见
import 'package:lib2/lib2.dart' hide foo;
复制代码
为了减少 APP 的启动时间,加载很少使用的功能,我们还可以延迟导入库。使用 deferred as
关键字延迟导入
import 'package:deferred/hello.dart' deferred as hello;// 当需要使用时,再通过库标识符调用 loadLibrary函数加载
hello.loadLibrary();
复制代码
异步编程
Dart与JavaScript一样,是一个单线程模型。但这并不意味着Dart中不能进行异步编程,只是这种异步编程区别于传统的多线程异步方式。
Dart中的所有代码都只在一个线程上运行,但Dart代码可以运行在多个isolate上。isolate可以看做一个微小的线程,isolate由虚拟机调度,isolate之间没有共享内存,因此它们之间没有竞争,不需要锁,不用担心死锁,因此开销小,性能高。由于没有共享内存,所以它们之间唯一的通信只能通过Port进行,而且Dart中的消息传递也总是异步的。
Dart中两种方式可以使用Future
对象来进行异步编程
- 使用
async
和await
关键字 - 使用 Future API
使用async
和await
编写代码非常简单,而且编写的代码看起来有点像同步代码,实际上是异步的。
// 导入io库,调用sleep函数
import 'dart:io';// 模拟耗时操作,调用sleep函数睡眠2秒
doTask() async{await sleep(const Duration(seconds:2));return "Ok";
}// 定义一个函数用于包装
test() async {var r = await doTask();print(r);
}void main(){print("main start");test();print("main end");
}
复制代码
运行结果:
main start
main end
Ok
复制代码
在函数签名中加入async
关键字,表示该函数异步执行,await
表示等待异步结果执行完成返回Future
对象。但有一点需要注意,await
只能在async
函数中出现,因此往往需要再定义一个async
函数,用于包装。上述代码中test
函数就是用于包装。
关于Dart异步编程的更多详细知识,请跳转本人另一篇博客 Dart 异步编程详解之一文全懂
以上是本篇的全部内容,关于博主的更多技术文章,请跳转到以下链接,谢谢!
我的个人博客
GitHub
Dart语言——45分钟快速入门
关注我的公众号:编程之路从0到1
Dart语言——45分钟快速入门(下)相关推荐
- Dart语言——45分钟快速入门(上)
文章目录 前言 视频课程 环境准备 安装Dart SDK 配置环境变量 配置 VSCode 编辑器 测试环境 基础语法 代码注释 内置数据类型 变量与常量 定义变量 定义常量 内置类型的常用操作 数值 ...
- Python语言十分钟快速入门
假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(CheatSheet ...
- python语言入门u-Python语言十分钟快速入门
[简介] Python(蟒蛇)是一种动态解释型的编程语言.Python可以在Windows.UNIX.MAC等多种操作系统上使用,也可以在Java..NET开发平台上使用. python logo [ ...
- python语言入门教程-Python语言十分钟快速入门
[简介] Python(蟒蛇)是一种动态解释型的编程语言.Python可以在Windows.UNIX.MAC等多种操作系统上使用,也可以在Java..NET开发平台上使用. python logo [ ...
- python语言入门-Python语言十分钟快速入门
[简介] Python(蟒蛇)是一种动态解释型的编程语言.Python可以在Windows.UNIX.MAC等多种操作系统上使用,也可以在Java..NET开发平台上使用. python logo [ ...
- python新手教程 从零开始-Python零基础从零开始学习Python十分钟快速入门
原标题:Python零基础从零开始学习Python十分钟快速入门 学习Python的,都知道Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言.Python是一种动态解释型的 ...
- 深入理解 Redis Template及4种序列化方式__spring boot整合redis实现RedisTemplate三分钟快速入门
概述 使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板类 RedisTemplate, 今天我们好好的看看这个模板类 . RedisTem ...
- thinkcmf搭建教程_5分钟快速入门
# 5分钟快速入门 [TOC=1,5] ## 1.创建模板目录 在`public/themes/`目录下创建`quick_start`目录 ## 2.添加模板描述文件 在`public/themes/ ...
- 不会几个框架,都不好意思说搞过前端: Vue.js - 60分钟快速入门
Vue.js--60分钟快速入门 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的 ...
最新文章
- UIAlertController
- 【Android】Activity生命周期
- 媒体播放控件导入到窗体中 winform 0131
- ajax error的用法,JQuery ajaxError()用法及代码示例
- Java json字符串转Object
- 论文笔记——分布式深度学习框架下基于性能感知的DBS—SGD算法
- abd串口工具使用教程_一体机电脑维修工具下载及使用教程
- python下使用gdal空间插值
- 执行SQL语句时出现问题操作必须使用一个可更新的查询错误的解决方法
- 复旦和同济计算机学硕,考研择校:复旦、同济、上财哪个更有前途?看网友怎么说!...
- java 总线_用于 Java 的服务总线库
- 【渝粤题库】广东开放大学 金融经济学 形成性考核
- mysql core dumped_关于Segmentation fault (core dumped)几个简单问题的整理
- Go 语言开发工具 LiteIDE X36 发布
- K8S 部署 skywalking
- python好用的编程工具
- Android模拟机设置中文输入法(拼音、手写、笔画等)
- 【028】仿猫眼、淘票票的电影后台管理和售票系统系统(含后台管理)(含源码、数据库、运行教程)
- 岗位po是什么意思_po主是什么意思
- 脚踏实地《数据结构第二章》第一节:线性表的定义和基本操作