Dart介绍
将 Dart 和 JavaScript 做一个对比:
- 开发效率高
Dart 运行时和编译器支持 Flutter 的两个关键特性的组合:
- 基于 JIT 的快速开发周期:Flutter 在开发阶段采用,采用 JIT 模式,这样就避免了每次改动都要进行编译,极大的节省了开发时间;
- 基于 AOT 的发布包: Flutter 在发布时可以通过 AOT 生成高效的机器码以保证应用性能。而 JavaScript 则不具有这个能力。
- 高性能
Flutter 旨在提供流畅、高保真的的 UI 体验。为了实现这一点,Flutter 中需要能够在每个动画帧中运行大量的代码。这意味着需要一种既能提供高性能的语言,而不会出现会丢帧的周期性暂停,而 Dart 支持 AOT,在这一点上可以做的比 JavaScript 更好。 - 快速内存分配
Flutter 框架使用函数式流,这使得它在很大程度上依赖于底层的内存分配器。因此,拥有一个能够有效地处理琐碎任务的内存分配器将显得十分重要,在缺乏此功能的语言中,Flutter 将无法有效地工作。当然 Chrome V8 的 JavaScript 引擎在内存分配上也已经做的很好,事实上 Dart 开发团队的很多成员都是来自Chrome 团队的,所以在内存分配上 Dart 并不能作为超越 JavaScript 的优势,而对于Flutter来说,它需要这样的特性,而 Dart 也正好满足而已。 - 类型安全和空安全
由于 Dart 是类型安全的语言,且 2.12 版本后也支持了空安全特性,所以 Dart 支持静态类型检测,可以在编译前发现一些类型的错误,并排除潜在问题,这一点对于前端开发者来说可能会更具有吸引力。与之不同的,JavaScript 是一个弱类型语言,也因此前端社区出现了很多给 JavaScript 代码添加静态类型检测的扩展语言和工具,如:微软的 TypeScript 以及Facebook 的 Flow。相比之下,Dart 本身就支持静态类型,这是它的一个重要优势。 - Dart 团队就在你身边
看似不起眼,实则举足轻重。由于有 Dart 团队的积极投入,Flutter 团队可以获得更多、更方便的支持,正如Flutter 官网所述“我们正与 Dart 社区进行密切合作,以改进 Dart 在 Flutter 中的使用。例如,当我们最初采用 Dart 时,该语言并没有提供生成原生二进制文件的工具链(这对于实现可预测的高性能具有很大的帮助),但是现在它实现了,因为 Dart 团队专门为 Flutter 构建了它。同样,Dart VM 之前已经针对吞吐量进行了优化,但团队现在正在优化 VM 的延迟时间,这对于 Flutter 的工作负载更为重要。”
软件安装
在这之前,我们知道”工欲善其事必先利其器“,所以需要安装相关工具。
Android studio安装
…
java安装
win7电脑看这篇博客。
Android studio中安装flutter与创建项目
首先,现在官网下载flutterSDK包,在此包里面包含了Dart 的SDK文件,下载路径如下:
在 Windows 操作系统上安装和配置 Flutter 开发环境 | Flutter 中文文档 - Flutter 中文开发者网站
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Owlizf64-1638454824682)(F:\flutter笔记\Dart_imges\image-20211117233302460.png)] flutter前端java_flutter前端java](https://s2.51cto.com/images/blog/202504/17113332_6800768ccb9b980694.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
点击蓝色按钮即可下载。
下载完成之后,将该文件包解压到你想安装目录的下面,我的安装目录是在D:\SoftwareFolder\路径下,将其解压。解压完成之后就是运行,flutter提供了两种运行方式:
- 通过运行flutter目录下的
flutter_console.bat文件,就可以在命令行中输入flutter命令了。
配置flutter环境
- 配置环境变量,进入
flutter\bin目录,将地址复制,然后打开环境变量窗口进行配置环境变量。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-USVM5Q22-1638454824684)(F:\flutter笔记\Dart_imges\image-20211117234900888.png)] flutter前端java_字符串_02](https://s2.51cto.com/images/blog/202504/17113333_6800768d3ef7b56594.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
检测是否可用:
按快捷键win+R输入cmd命令,在命令行中输入flutter doctor。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gfo7uGW5-1638454824685)(F:\flutter笔记\Dart_imges\image-20211117235243803.png)] flutter前端java_字符串_03](https://s2.51cto.com/images/blog/202504/17113333_6800768db73ff63734.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
在Android studio中添加 Command-line Tools
打开 Android studio,在stting->appearance &Behavior->System Settings->Android SDK中进行配置。

但是出现了错误,没关系,先解决第一个框里面的问题。
添加许可证
它提示Android toolchain - develop for Android devices,
说明是Android的SDK协议没有添加许可证,
找到自己android—sdk的路径,比如:G:\studioAnZhuang\AndroidStudioSDK\tools\bin,关键是**\tools\bin**。
在此目录打开 cmd 命令行 输入以下命令:
sdkmanager --licenses
然后一路同意y就可以了,最后在命令行下输入flutter doctor 查看结果。
配置模拟器路径
之后关闭此命令行窗口,再次运行flutter doctor发现还是这两个问题,于是看见它找出的问题是Unable to locate Android SKD,这就要涉及到配置环境变量的问题,找到你的Android sdk安装路径,比如我的安装路径如下图。

由于我不确定是不是这个路径,去环境变量里添加了这个之后,发现可行,把我激动坏了,环境变量配置如下所示。

关闭命令行窗口之后,再次运行flutter doctor如下图所示。

不知道为啥,就是特别兴奋,感觉满满的成就感,哈哈哈,但是一想到还有一个问题没有解决,脑壳又大了。
于是分析了一下,发现是没有安装谷歌的原因,于是我通过下面链接去下载了google浏览器。
它给我自动安装在了C盘,由于不知道怎么更改路径,就挺无语的,再次运行flutter doctor就没有报错了,如下图所示。

配置完这些东西之后,我们还需要去环境变量中添加2个路径如下图所示。

盘符名:安装文件夹\flutter_windows_2.5.3-stable\flutter\bin\cache\dart-sdk\bin
- dart的环境变量,在
flutter2.0之后,官网的安装包里面就自带了dart的sdk文件,所以,我们只需要找到它的文件位置,将它的环境变量设置好就可以开始肝代码了。将下面的路径添加到系统环境变量中。
盘符名:安装文件夹\flutter_windows_2.5.3-stable\flutter.pub-cache\bin
- Pub下载的公共模块的执行路径,如果,没有
bin文件夹,创建一个即可。
有了上面这些操作,我们就可以配置编译器,开始在编译器中肝代码了!!激动的心,颤抖的手,终于要开始了。
创建项目
Android studio中创建项目
在Android stduio中安装插件:

重启软件,

创建Dart项目
首先,打开Android studio软件,点击File > New >New Flutter Project...
选择Dart添加Dart sdk文件位置,如下如图所示。

点击Next,创建项目名和项目地址,之后点击Finish,即可创建项目。

创建Dart文件
首先,找到Project面板,在空白区域右击,选择new>Dart File>输入你的文件名,即可创建你的dart文件。


写一段代码测试是否可以运行。

写完之后,点击mian方法旁边的
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yybDmqgr-1638454824687)(F:\flutter笔记\Dart_imges\image-20211118172025554.png)] flutter前端java_Dart_17](https://s2.51cto.com/images/blog/202504/17113337_68007691dede995554.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
按钮运行,并查看结果如下图。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tGvmLFPV-1638454824688)(F:\flutter笔记\Dart_imges\image-20211118172207260.png)] flutter前端java_dart_18](https://s2.51cto.com/images/blog/202504/17113338_680076921ac828490.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
如果发现无法运行,请点击下面图中的第一个框,进行选择模拟器,再点击运行。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9bri8Vy-1638454824688)(F:\flutter笔记\Dart_imges\image-20211118172712132.png)] flutter前端java_flutter前端java_19](https://s2.51cto.com/images/blog/202504/17113338_680076927428a70681.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
VScode安装
首次,在VScode官网进行下载,链接如下。
安装特别简单,若有不会,请访问下面链接。
安装之后,我们需要在软件中安装flutter插件和run插件,如下图所示。


-
flutter插件安装好之后,重启一下vscode就可以开始创建文件,编写代码。 run插件可以直接点击右上角的
,前提是你需要在文档中写了Dart程序代码。
VScode中创建项目
- 首先,你需要在你所需要创建项目的目录下使用
cmd命令,进入命令行,使用flutter create flutter_app。 flutter_app是你需要创建的项目名。- 在vscode打开项目,找到
android目录下的build.gradle文件并且打开。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lv045wQj-1638454824690)(F:\flutter笔记\Dart_imges\image-20211122141455474.png)] flutter前端java_dart_22](https://s2.51cto.com/images/blog/202504/17113339_680076937878a83131.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
在打开的文件中,将repositories{...}下的google()和mavenCentral()注释,因为我们要换源,使用国内的镜像源。将下面3个源替换原来的两个源。
maven { url ‘https://maven.aliyun.com/repository/google’}
maven { url ‘https://maven.aliyun.com/repository/jcenter’ }
maven { url ‘https://maven.aliyun.com/repository/public’ }
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmQMWYSA-1638454824691)(F:\flutter笔记\Dart_imges\image-20211122141955329.png)] flutter前端java_Dart_23](https://s2.51cto.com/images/blog/202504/17113339_68007693ce2b311029.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
之后打开你的flutter安装目录,找到目录下的packages > flutter_tools > gradle >flutter.gradle> 的文件,双击在vscode中打开,将repositories{...}下面的代码替换。保存,重新打开vscode。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pgd0FoHe-1638454824691)(F:\flutter笔记\Dart_imges\image-20211122142408354.png)] flutter前端java_flutter_24](https://s2.51cto.com/images/blog/202504/17113340_6800769419c5d6020.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
添加第三方包(依赖)
说完了安装方法,现在介绍两种添加Flutter第三方包的两种方法:
- 在
flutter项目的pubspec.yaml文件中添加:
在该文件中找到dependencies:所在的行,并且需要知道它的版本号,所以,打开https://pub.dev/,在这里面你可以搜索到所有开源的第三方包。
例如添加一个provider的包:
将版本号复制下来,粘贴到该文件中的dependencies处,点击Pub get,在下面的Messges窗口中可以看到是否添加成功,若成功之后,可以在External Libraries中查看文件的位置。 - 在命令行中添加:
添加成功!
Dart基础
语法基础
简单介绍
首先,我们需要知道程序是都是从main方法开始执行,于是有了固定的写法,如下所示。
// 定义一个输出方法
void printInteger(int num){
print("hello world $num"); // 输入语句,将文本输出到控制台
// $num 用于将形参的值放进来
}
// 在主函数中输出
void main(){
var number = 3000; // 定义一个活动变量,可以是任意类型值
printInteger(number); // 调用方法
}从上面可以看出:
- 在main方法后面是一对小括号与一对大括号。
- 大括号里面放置的是需要执行的程序语句。
- 函数和方法前面都有类型声明,
void关键字表示该方法无返回值,int是整形数字。 - 两根斜杠为注释内容,程序不会执行被注释的内容。
- 打印使用print(
JavaScript中使用console.log())。 - 每行代码结束时,必须写结束分号。
- 字符串通过引号包起来,支持模板字符串。
- 用
var声明的变量。其数据类型是动态的。 - 声明函数不需要关键字(
JavaScript中使用function关键字声明函数)。
注释
在Dart中,注释有两种写法,和javascript的注释方法一样,如下所示。
- 单行注释,以
//两根斜杠为注释。
// 这行文本被注释- 多行注释,以
/* 这里边是文本内容 */,以两根斜杠为边,里面再放两个星号,在星号中的文本就是注释内容。
/*
这行文本被注释
这行文本被注释
*/- 文档注释,使用三跟斜杠用于文档注释,可以通过
dartdoc将注释转换为文档(文档注释支持markdown语法)。
/// 这是文档注释变量
- 变量是一个引用,Dart万物皆对象,变量存储的是对象的引用。
- 声明变量
- 明确指定类型:
int age = 18; - 不明确类型:
var age = 18;dynamic age = 18;Object age = 18。Object是Dart所有对象的根基类,也就是说在 Dart 中所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象。dynamic与Object声明的变量都可以赋值任意对象,且后期可以改变赋值的类型,这和var是不同的,如:
var t;
dynamic t;
Object x;
var t = "ha";
t = "hi world";
x = 'Hello Object';
//下面代码没有问题
t = 1000; // 出错
//下面代码没有问题
t = 1000;
x = 1000;dynamic与Object不同的是dynamic声明的对象编译器会提供所有可能的组合,而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错。
dynamic a;
Object b = "";
main() {
a = "";
printLengths();
}
printLengths() {
// 正常
print(a.length);
// 报错 The getter 'length' is not defined for the class 'Object'
print(b.length);
}dynamic的这个特点使得我们在使用它时需要格外注意,这很容易引入一个运行时错误,比如下面代码在编译时不会报错,而在运行时会报错:
print(a.xx); // a是字符串,没有"xx"属性,编译时不会报错,运行时会报错- 变量名大小写敏感(age与Age是两个不同的变量)。
Dart变量的值不会进行隐式转换(null不会自动 转换成false)。
void main() {
//定义变量
var name1="张三";
print(name1); // 输出字符串 张三
// 指定类型的变量
String name2 = "李四";
print(name2); // 输出String类型的字符串 李四
// 任意类型的变量
dynamic name3 = "王五";
print(name3); // 输出字符串 王五
// 任意类型的变量
Object name4 = "赵六";
print(name4); // 输出字符串 赵六
}常量
- 常量就是值不可以改变的变量(一旦声明,其值不能改变)。
- 声明常量
- 使用
const关键字进行声明变量。
const age = 18;- 使用
final关键字进行声明变量。
final age = 18;const与final的区别
-
const time=DateTime.now();//报错-无法将运行时得知分配给const变量。 -
final time = DateTime.now();//成功-可以将运行时的值分配给final变量。
void main(List<String> args) {
// const定义常量
const age = 18;
// age = 19; // 报错,常量不能再次赋值
print(age); // 输出整形 18
// final定义常量
final age1 = 18;
// age1 = 19; // 报错,常量不能再次赋值
print(age1);
// 报错-无法将运行时得知分配给`const`变量
// Cannot invoke a non-'const' constructor where a const expression is expected.
// const time1=DateTime.now();
// 成功-可以将运行时的值分配给`final`变量
final time2=DateTime.now();
print(time2);
}数据类型
Number类型
- Dart中的数字由三个关键字描述
num数字类型(既可以是整数,也可以是小数)
-
int表示整数(必须是整数) -
double表示浮点数(既可以是整数,也可以是小数)
- 常用API
- https://api.dart.cn/stable/dart-core/num-class.html
- https://api.dart.cn/stable/dart-core/int-class.html
- https://api.dart.cn/stable/dart-core/double-class.html
void main(List<String> args) {
// 定义一个整型变量
int num1 = 123;
print(num1); // 123
// 定义一个浮点数变量
double num2 = 123;
print(num2); // 123.0
// 定义一个数值变量,它包含了int类型和double类型
num num3 = 123;
print(num3); // 123
num num4 = 123.0;
print(num4); // 123.0
}常用API
String类型
字符串定义
首先,我们需要知道怎么定义字符串,字符串定义的引号都是成对出现,字符串的定义方法如下:
- 使用var的方式进行定义。
var str1 = 'this is str1'; // 单引号形式
var str2 = "this is str2"; // 双引号新式// 输出结果如下所示
this is str1
this is str2- 使用String定义字符串,3个引号包括换行符。
String str1 = 'this is str1'; // 单引号形式
String str2 = "this is str2"; // 双引号新式
String str3 = '''
this is str3
this is str3'''; // 实现多行显示,原样显示// 输出结果如下所示
this is str1
this is str2
this is str3
this is str3- 正则表达式。
- RegExp(r’正则表达式’)
- RegExp(r’\d+')
字符串拼接
首先,我们需要定义两个字符串变量,然后将他们拼接起来。
- 使用
+加号将他们连接。
// 字符串拼接
String str1 = "张三想:";
String str2 = "吃饭";
print(str1+str2);
//或者
String str3 = str1 + str2;
print(str3);// 效果如下
张三想:吃饭
张三想:吃饭- 使用
$方式进行拼接操作。
String str1 = "张三想:";
String str2 = "吃饭";
print("$str1 $str2");张三想: 吃饭字符串的常见操作
- 使用字符分割,结果是一个数组类型的值。
-
.split("字符")– 根据字符进行分割。
// 字符串分割
String str1 = "hello world";
print(str1.split(""));; // 按照空值进行分割[h, e, l, l, o, , w, o, r, l, d]- 字符串裁切
-
.trim()– 将字符串前后空格裁切掉。 -
.trimLeft()– 将字符串的左边空格裁切。 -
.trimLeft()– 将字符串的右边空格裁切。
// 字符串裁切
String str1 = " hello world ";
print(str1.trim()); // 删除前后空格
print(str1.trimLeft()); // 删除左边空格
print(str1.trimRight()); // 删除右边空格hello world
hello world
hello world- 判断字符串是否为空
-
.isEmpty– 判断字符串是否为空,返回值是 true或 false。 -
.isNotEmpty– 判断字符串是否不为空,返回值是 true或 false。
// 判断字符串是否为空
String str1 = ""; // 定义空字符串
print(str1.isEmpty);
print(str1.isNotEmpty);true
false- 字符串替换
-
.replaceAll(旧字符,新字符),而.replaceFirst()只查找第一个并替换。
// 字符串替换
String str1 = "hello dart,hello world";
print(str1.replaceAll("hello", "你好"));- 查找字符
-
.contains('字符串')– 在字符串中查找字符,返回值为true 或 false。
// 字符查找
String str1 = "hello dart,hello world";
print(str1.contains("l"));true- 定位字符
-
.indexOf(字符)– 用于在找到字符的索引位置,返回索引下标,从左开始查找。 -
.lastIndexOf(字符)– 找到字符的索引位置,返回索引下标,从右往左查找。
// 定位字符
String str1 = "hello dart,hello world";
print(str1.indexOf('ll'));
print(str1.lastIndexOf("or"));2
18bool类型
- 布尔类型只有
true和false。 - Dart通过bool关键字来表示布尔类型。
- 对变量进行判断时,要显式的检查布尔值
- if (varname){ … }
- if (varname == 0){ … }
- if (varname == null){ … }
// 定义一个true值
bool b1 = true;
print(b1);
// 定义一个false值
bool b2 = false;
print(b2);true
false显式的判断
- 与if语句,将条件
true赋值给一个变量保存,将其放入if的判断中进行判断,使用如下:
bool b3 = true;
if (b3) {
print("条件成立!");
}else{
print("条件不成立");
}条件成立!- 判断字符是否为 NaN。
var b1 =0/0;
print(b1.isNaN);true- 判断是否为空值。
// 判断是否为空值
var flag;
if (flag == Null) {
print("是空值");
} else {
print("不是空值");
}List数据类型
List用法
List 就是Dart中的数组,由List对象表示。List有两种声明方式:
- 字面量方式
- 创建列表。
List list = [1,2,"张三","不法分子"]; // 不限定元素的数据类型- 泛型方法限定列表类型。
List list = <int>[1,2,3]; // 泛型,限定元素的类型是int- 构造函数方式
- 创建一个不限定长度的列表。
List list = new List.empty(growable:true); // 不限制长度的空列表[]- 填充指定长度的列表。
List list = new List.filled(3,6); // 声明指定长度的填充列表[6, 6, 6]- 扩展操作符(…)
- 将第一个列表插入到另一个列表中。
var list = [1,2,3];
var list2 = [0,...list];[0, 1, 2, 3]- 使用
?先进行判断是否可以扩展,在下面列子中用空值进行试验。
// 判断是否可以扩展
var list;
// var list1 = [123,...list]; //报错:type 'Null' is not a subtype of type 'Iterable<dynamic>'
var list2 = [234,...?list];
print(list2);List常用API
- 添加元素
.add(数据)– 向列表中添加元素,可以是字符串、数组、各种数据类型。
// 添加元素
List list = [12,23,34];
list.add(1.3);
list.add("字符串");
list.add([true,false]);
print(list);[12, 23, 34, 1.3, 字符串, [true, false]].addAll(iterable)– iterable是一个可迭代的对象,可以在里面放置多个元素。
// 添加元素
List list = [12,23,34];
list.addAll(["name",123,["张三",18]]);
print(list);[12, 23, 34, name, 123, [张三, 18]]- 在指定位置添加元素。
.insert(index,element)– index为元素下标,element为元素
// 在指定位置添加元素
List list = [12,23,34,45,56];
list.insert(3, "张三"); // 在下标为3的地方添加“张三”
print(list);[12, 23, 34, 张三, 45, 56]- 清空列表
.clear()– 清空列表。
// 清空列表
List list = [12,23,34,45,56];
list.clear();
print(list);[]- 连接元素
-
.join('-')- -将列表中的元素使用 - 连接。
- 删除元素
.remove(元素名)– 参数为需要删除的元素名。
List list = [12,23,34,45,56];
list.remove(23);
print(list);[12, 34, 45, 56].removeAt(下标)– 根据下标删除元素。
// 根据下标删除元素
List list = [12,23,34,45,56];
list.removeAt(list.length-1);
print(list);[12, 23, 34, 45]- 返回数组长度
.length– 可以查看数组有少个元素。
// 查看数组长度
List list = [12,23,34,45,56];
print(list.length);5- 创建一个固定长度的列表
.filled(元素个数,填充的字符)--所接收的元素类型一定是List类型,创建的列表长度是固定的,不可以修改他的长度。
List list = List.filled(3,6); // 声明指定长度的填充列表
print(list);[6, 6, 6]- 指定创建指定类型与长度的列表。
// 创建指定类型的快速填充
List list = List<String>.filled(3,""); // 所创建的列表中只能添加int类型的元素。
list[0]="张三";
print(list);[张三, , ]- 列表反转
.reversed– 将列表中的元素翻转,得到的结果是一个元组,可以使用在后面加上.toList()方法.
// 列表的反转
List list = [12,23,34,45,56];
print(list.reversed);
// 变为列表
print(list.reversed.toList());(56, 45, 34, 23, 12)
[56, 45, 34, 23, 12]遍历列表
- forEach()
- 遍历列表
- map()
- 遍历并处理元素,然后生成新的列表
- where()
- 返回满足条件的数据
- any()
- 只有一项满足条件,即返回true
- every()
- 判断是否每一项都满足条件,都满足条件才返回true
- 使用
for循环进行遍历。
// for 循环进行遍历
var list = [1,2,3];
for (var i = 0; i < list.length; i++) {
print(list[i]);
}1
2
3- for … in 循环。
// for in 循环进行遍历
var list = [1,2,3];
for (var item in list) {
print(item);
}1
2
3- forEach 使用匿名函数进行遍历,其中element是一个形参,使用print可将他打印出来。
// forEach
var list = [1,2,3];
list.forEach((element) {
print(element);
});1
2
3- 使用map()将列表中的每个元素进行相乘,得到一个处理之后的列表,注意:
=>函数只能右一行,可以省略大括号。
// map
var list = [1,2,3];
list.map((e)=> e*e); // 也可以写成这样list.map((e)=> {e*e});
print(list);
}[1, 2, 3]- where()返回符合条件的元素
//where()返回符合条件的元素
// 判断数字是否为奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
var oddNum = list.where((element) => isOdd(element)); // 返回结果是一个元组类型
print(oddNum.toList());[1, 3, 5, 7]- 第五行代码中,调用
isOdd()函数进行判断,将判断的结果返回给list,并重复判断,直到不满足条件为止。而element则是列表中的每一个元素。
- 使用any()检测是否有奇数,返回值为true或false。有一个也是true。
// 使用any() 检测是否奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
print(list.any(isOdd));true- 使用every()来判断是否都是奇数。
// 使用every()来判断是否都是奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
print(list.every(isOdd));false- 使用扩展方式,通过
.expend()方法进行降维处理。
// 扩展,使用expend进行降维
var list = [[1,2,3],[4,5,6]];
var flattened = list.expand((element) => element).toList();
print(flattened);- 折叠--
.fold(initialValue, (previousValue, element) => null),initialValue
为初始值,对列表中的每一个元素,做一个累计的操作。
// 折叠
var list = [1,2,3,4,5,6];
int result = list.fold(2, (previousValue, element) => previousValue+element);
print(result);Set类型
- Set是一个无序的,元素唯一的集合,不能有重复值。
- Set有字面量和构造函数两种声明方式(字面量中用大括号)。
- 无法通过下标取值。
- 具有集合特有的操作。比如:求交集、并集、差集等。
- 字面量
// 字面量
var nums = <int>{1,2,3};
print(nums);{1, 2, 3}- 构造函数的形式创建集合
// 构造函数创建集合
var fruits = new Set(); // 使用构造函数的形式创建集合
fruits.add("张三"); // 向集合中添加添加元素
fruits.add("李四");
fruits.add("王五");
print(fruits); // 打印集合
print(fruits.toList()); // 集合转换为表格形式{张三, 李四, 王五}
[张三, 李四, 王五]- 列表转换为集合
// 表格转换为集合,重复的元素会被过滤掉
List list = [1,2,2,3,4,4]; // 定义列表
print(list.toSet()); // 列表转换为集合{1, 2, 3, 4}- 集合特有的操作,交集、差集、并集。
// 集合特有操作
var name1 = new Set();
name1.addAll(['张山','李四',"王五"]);
var name2 = new Set();
name2.addAll(["王五","赵六","马七"]);
// 求交集,共同有的元素会被显示出来了。
print(name1.intersection(name2));
// 求并集,将他们合并,共同的元素只留一个。
print(name1.union(name2));
// 求差集,第一个中有的,而第二个中没有的元素。
print(name1.difference(name2));
// 返回第一个元素
print(name1.first);
// 返回最后一个元素
print(name1.last);Map类型
- Map是一个无序的键值对(key-value)映射。通常被作为哈希或字典。]
- Map的键值对是成对出现的。
- 声明方式:
var map = {key1:value1,key2:value2};var map = new Map();map['key'] = value;- 字面量形式
// 字面量形式
var person = {
'name':'张三',
'age':18,
'information':'法外狂徒',
};
print(person);{name: 张三, age: 18, information: 法外狂徒}- 构造函数
// 构造函数
var p = new Map();
p['name'] = "张三"; // 向map中添加元素
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
// 访问属性
print(p['name']); // 访问name的值{name: 张三, age: 18, information: 法外狂徒}
{name: 张三, age: 18, info: 法外狂徒}
张三- 判断Map中的Key和Value是否存在,返回值为true或false。
var p = new Map();
p['name'] = "张三";
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
// 判断Map中的Key是否存在
print(p.containsKey('name'));
// 判断Map中的Value是否存在
print(p.containsValue('张山'));true
false.putIfAbsent()赋值,如果 Key 不存在,我们才赋值(如果key已存在,则不赋值)。
var p = new Map();
p['name'] = "张三";
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
//如果 Key 不存在,向Key赋值
p.putIfAbsent('score', () => 100);
print(p);{name: 张三, age: 18, info: 法外狂徒, score: 100}.keys和.values获取map中所有的key 和 value。
// 获取所有的key 和 value
var person = {'name':'张三','age':18,'information':'法外狂徒'};
print(person.keys);
print(person.values);(name, age, information)
(张三, 18, 法外狂徒)- 删除元素
.remove(key)– 根据key 进行删除。
// 删除元素
var person = {'name':'张三','age':18,'information':'法外狂徒'};
person.remove('name');
print(person);{age: 18, information: 法外狂徒}.removeWhere()– 根据条件进行删除。
// 根据条件进行删除
var person = {'name':'张三','age':18,'information':'法外狂徒'};
person.removeWhere((key, value) => key=='name');
print(person);{age: 18, information: 法外狂徒}其他数据类型
- Runes(符文)
- Runes对象是一个32位字符对象。它可以把文字转换成符号表情或特定的文字。
- print(‘\u{1f44d}’) => 👍
- https://copychar.cc/
- Symbol
- 在Dart 中符号用
#开头来表示的标识符。
- dynamic
- 动态数据类型
运算符(operator)
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。Dart语言内置了丰富的运算符,并提供了以下类型的运算符:算术运算符、关系运算符、类型判断运算符、赋值运算符、逻辑运算符、按位和移位运算符、条件表达式、级联运算符以及其他运算符。
- 地板除(~/)-- 相除之后,向下取整。
- 类型判断运算符(is |is!)-- 判断某种变量是否属于某种类型。
- 避空运算符(?? | ??=) – 如果变量为空,才会对变量赋值,变量不为空,不对其做任何操作。
- 条件属性访问(?.) – 先判断属性是否存在,存在的话再去访问。
- 级联运算符(…)
myObject.myMethod(); // 返回myMethod的返回值myObject..myMethod(); // 返回myMethod()对象的引用~/地板除,相除之后,向下取整
// 地板除
print(5/3); // 除法
print(5~/3); // 地板除1.6666666666666667
1-
is和is!类型判断运算符
// 类型判断运算符
List list = []; // 定义一个列表
// is运算符
if (list is List) { // 判断是否是列表
print("是List");
} else {
print("不是List");
}
// is! 运算符
if (list is! List) {
print("不是列表");
} else {
print("是列表");
}是List
是列表??和??=避空运算符
// 避空运算符
print(1 ?? 3); //返回1,因为1不为空
print(null ?? 11); // 返回11,因为第一个参数为null
var name; //name没有赋值,为空。
print(name ?? "name为空");
// 赋值避空运算符
name ??= "张三"; //进行判断,如果为空,将张三赋值给name
print(name);1
11
name为空
张三- 条件属性运算符
// 条件属性运算符(判断可能为空的属性)
var m = new Map();
print(m.length); // 返回0
var obj;
// print(obj.length); //The getter 'length' was called on null.
print(obj?.length); // 返回null0
null- 级联运算符
// 级联运算符
// 普通添加删除数据
Set s =new Set();
s.add("张三");
s.add("李四");
s.add([1,2,3]);
s.removeWhere((element) => element=="张三");
print(s);
// 级联添加删除数据
Set set = new Set();
set..add("张山")
..add("赵陆")
..add([1,2,3])
..removeWhere((element) => element=="张三");
print(set);算数运算符(Arithmetic Operators)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cpQLAH98-1638454824693)(F:\flutter笔记\Dart_imges\image-20211120170520611.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j755TOBt-1638454824693)(F:\flutter笔记\Dart_imges\image-20211120170555298.png)]
// 算数运算符
print(2 + 3 == 5);
print(2 - 3 == -1);
print(2 * 3 == 6);
print(5 / 2 == 2.5); // 结果是一个浮点数
print(5 ~/ 2 == 2); // 结果是一个整数
print(5 % 2 == 1); // 取余
print('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
// 自增自减运算符
var a, b;
a = 0;
b = ++a; // 在 b 赋值前将 a 增加 1。
print(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 赋值后将 a 增加 1。
print(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 赋值前将 a 减少 1。
print(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 赋值后将 a 减少 1。
print(a != b); // -1 != 0关系运算符(Relational operators)
用法基本上和其他语言相同。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUVseTGm-1638454824694)(F:\flutter笔记\Dart_imges\image-20211120172117279.png)] flutter前端java_flutter前端java_25](https://s2.51cto.com/images/blog/202504/17113342_680076969df0038898.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
类型判断运算符
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nS8oL1WJ-1638454824695)(F:\flutter笔记\Dart_imges\image-20211120172817600.png)] flutter前端java_flutter前端java_26](https://s2.51cto.com/images/blog/202504/17113342_68007696d96cb25004.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
赋值运算符
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MB7XT0p-1638454824695)(F:\flutter笔记\Dart_imges\image-20211120172913856.png)] flutter前端java_字符串_27](https://s2.51cto.com/images/blog/202504/17113343_680076971e87537991.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
逻辑运算符
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xJUlUV0F-1638454824696)(F:\flutter笔记\Dart_imges\image-20211120172941265.png)] flutter前端java_dart_28](https://s2.51cto.com/images/blog/202504/17113343_68007697540ca95476.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
按位和移位运算符
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-czXC23LA-1638454824697)(F:\flutter笔记\Dart_imges\image-20211120173013759.png)] flutter前端java_dart_29](https://s2.51cto.com/images/blog/202504/17113343_680076979511b67714.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
其他运算符
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PtOKcIAb-1638454824697)(F:\flutter笔记\Dart_imges\image-20211120173042224.png)] flutter前端java_flutter前端java_30](https://s2.51cto.com/images/blog/202504/17113343_68007697e1b5c6085.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
三个点 和 两个点
使用...可以进行拼接操作,两个..表示级联操作。
三个点
List a = ["张三","李四","王五"];
List b = ["赵六","马奇","黄八"];
List c = [...a,...b];
print(c);
// 结果为:[张三, 李四, 王五, 赵六, 马奇, 黄八]
Map map1 = {'张三':'1','李四':'2','王五':'3',};
Map map2 = {'赵六':'4','马奇':'5','黄八':'6',};
Map map3 = {...map2,...map1};
print(map3);
// 结果为:{赵六: 4, 马奇: 5, 黄八: 6, 张三: 1, 李四: 2, 王五: 3}两个点
class Test {
//正常写法
A printfA() {
var a = A();
a.a();
a.b();
a.c();
return a;
}
//级联写法
A printfA() {
return A()..a()..b()..c();
}
}
class A {
a() {}
b() {}
c() {}
}函数
声明函数
- 直接声明
- Dart中声明函数不需要function关键字
- 箭头函数
- Dart中的箭头中,函数体只能写一行且不能带有结束的分号。
- Dart中的箭头函数,只是函数的一种简写形式。
- 匿名函数
- 立即执行函数
声明函数和调用函数
// 定义函数
void printInfo(){ // 无参函数,无返回值
print("hello world!");
}
int getNum(){ // 有返回值,无参函数
// return "张三"; // 不能返回String类型值
return 18; // int类型声明的函数只能返回int类型的值
}
void main(List<String> args) {
printInfo(); // 调用函数
int a = getNum(); // 接收函数返回值
print(a);
}hello world!
18- void 表示无返回值。
- return表示返回,但需要根据函数类型进行返回。也就是说函数是什么类型,返回值就是什么类型,而用于接收它的变量类型等级必须高于int类型。
- 调用函数,如果函数是有参函数,需要为函数传参,才能调用。
匿名函数
void main(List<String> args) {
// 匿名函数
var myPrint = (value){ // 定义一个匿名函数
print(value);
};
List fruits = ["苹果","香蕉","西瓜"];// 定义一个列表、
// fruits.forEach((element) {element});
fruits.forEach(myPrint);
}苹果
香蕉
西瓜- 第三行定义了一个匿名函数,并且用myPrint变量接收。
- 第七行定义了一个列表。
- 在第9行中使用
myPrint替换了(element) {element},原因是在.forEach()方法中传入的也是一个匿名函数。
箭头函数
只能一行显示的简单函数,并且没有分号。
// 箭头函数
List fruits = ["苹果","香蕉","西瓜"];
fruits.forEach((element) =>{
print(element) // 箭头函数中不能有分号,并且只能有一行
});
fruits.forEach((element) =>print(element)); // 只能有一行苹果
香蕉
西瓜
苹果
香蕉
西瓜立即执行函数
立即执行函数就是立即执行的函数。
// 立即执行函数
(
(int n){
print(n);
}
)(1223556);1223556- 使用一对小括号扩起来的匿名函数。
- 在小括号后面可以传递参数。
函数参数
- 必填参数
- 参数类型 参数名称
- 可选参数
- 放在必选参数后面
- 通过中括号包起来
- 带默认值的可选参数
- 命名参数
- 用大括号包起来
- 调用函数时,命名参数的名称与声明函数中的名称保持一致。
- 函数参数
- 把一个函数的实例当做参数传递给另一个参数
必填参数
// 定义一个String类型的必选参数
String userInfo(String name){
return '你好:$name';
}
void main(List<String> args) {
// 必填参数
// String res = userInfo(123); // 传入的值必须和定义值类型一样
String res = userInfo("张三");
print(res);
}你好:张三- 传入的值必须和定义值类型一样。
- 定义多个函数时,函数名不能相同,没有Java中的重载机制。
可选参数
// 可选参数
// // 必须给age定一个默认值,如果为null会和int类型冲突。或者使用动态类型 dynamic 和 Object类型
// String userInfo(String name,[int age=0]) // int类型
// String userInfo(String name,[dynamic age]) // Object类型
String userInfo(String name,[Object age=0]){
return '你好:$name,年龄:$age';
}
void main(List<String> args) {
// 必填参数
// String res = userInfo(123); // 传入的值必须和定义值类型一样
String res =userInfo("张三",18);
print(res);
}- 形参类型必须与实参类型一致。
- 可选参数用中括号包裹起来。
命名参数
// 命名参数
String userInfo(String name,{int age=0}){ // 使用花括符进行定义,int类型必须赋值
return '你好:$name,年龄:$age';
}
void main(List<String> args) {
// 命名参数调用时,必须与声明的形参一致
String res =userInfo("张三",age:18); // 使用键值对的形式进行传递参数
print(res);你好:张三,年龄:18- 命名参数使用花括号包裹起来。
- 调用时使用
属性名:属性值的形式进行传参。
函数参数
// 函数参数
var myPrint = (value){ // 定义一个匿名函数
print(value);
};
List fruits = ["苹果","香蕉","西瓜"];// 定义一个列表、
// 将匿名函数传递给forEach函数
fruits.forEach(myPrint);苹果
香蕉
西瓜- 将匿名函数用值得形式作为forEach函数的值进行传递。
作用域与闭包
函数作用域
- 内层可以访问外层所定义的内容。
- 外层不可以访问内层所定义的内容。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8CM0lOs5-1638454824698)(F:\flutter笔记\Dart_imges\image-20211121152031141.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0F3ZnDqs-1638454824699)(F:\flutter笔记\Dart_imges\image-20211121152136184.png)] flutter前端java_flutter_31](https://s2.51cto.com/images/blog/202504/17113344_680076981f42869118.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184)
闭包
- Dart中闭包的实现方式与JavaScript中完全一致。
- 使用时机:既能重用变量,又保护变量不被污染。
- 实现原理:外层函数被调用后,外层函数的作用域对象(AO)被内层函数引用着,导致外层函数的作用域对象无法释放,从而形成闭包。
parent(){
var money = 1000;
return (){
money-=100;
print(money);
};
}
var p = parent(); // 将parent函数保存为p函数
p(); // 每次调用完之后只释放return里面的匿名函数的地址,并没有parent函数的地址。
p(); // 所以可以一直调用一直减
p();900
800
700异步函数
- JavaScript中,异步调用通过Promise来实现
- async(异步)函数返回一个Promise(承诺)。await(等待)用于等待Promise。
- Dart中,异步调用通过Future(未来)来实现。
- async函数返回一个Future,await用于等待Fature。
…
类与对象
类-简介
- 类是通过class声明的代码段,包含属性和方法。
- 属性:用来描述类的变量。
- 方法:类中的函数。
- 对象是类的实例化结果(var obj=new MyClass())
- 在>=Dart 2.12的版本中添加了late关键字,在类中定义的空属性需要使用late关键字
- 类名首字母大写,其余字母单词首字母也必须大写。
- 类相当于一个模板,对象就是根据模板做出来的东西。
- 类只是抽象的说说,并不会去实现,而对象需要具体干出这些活。
- 就像你女朋友就是一个类,只知道指挥,而你就是她的对象,通过她发出的指令去做,啥都要干。
- 如果类特别多的话,可以将类单独放入一个文件中,用调用方式进行使用。
- 编程方式
- 面向对象编程(OOP)
- 面向过程编程(POP)
- JavaScript就是 面向过程编程,它的class只是语法糖,语法糖让程序更加简洁,有更高的可读性。
- JavaScript中没有类。
- Dart中所有的内容都是对象。
声明类
- 使用
class关键字进行定义类,类名后面是一对花括符,如:class 类名{}; - 实例化类使用
new关键字。 - 在
new对象的时候类名后面需要写一对小括号,比如:类型 对象名 = new 类名();
// 声明类
class Person{
// 类的属性
String name = "张三";
// 类的方法
void getInfo(){
print("我是$name");
}
}
void main(List<String> args) {
// 实例化类,得到一个对象
Person p = new Person();
// 访问类中的属性
print(p.name);
// 访问类中的方法
p.getInfo();
}张三
我是张三dart中所有的内容都是对象。
为什么这么说呢?看下面例子。
// new一个Map对象,Map是Dart中内置的一个类,不需要自己创建
Map m = new Map();[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cFrApKDO-1638454824699)(F:\flutter笔记\Dart_imges\image-20211121170336802.png)]
- 第一个大框中,在vscode中,类的属性是通过[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utIzZydm-1638454824700)(F:\flutter笔记\Dart_imges\image-20211121170527252.png)]来定义的。
- 第二个大框中,在vscode里,类的方法是通过[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPUCmBD3-1638454824701)(F:\flutter笔记\Dart_imges\image-20211121170922049.png)]来定义的。
- 基本上每个东西自己的属性和方法。
将类放入单独的文件中
在当前目录中创建一个lib目录,在该目录中创建一个叫lei.dart文件,在文件中写入一个类,如下所示:
// lei.dart
// 创建一个人类
class Person{
int a =10;
late int b; // 创建一个空值b
// 有参构造函数
Person(this.a,this.b){
print('${a} $b');
}
// 命名构造函数
Person.info(){
print("这是命名构造函数");
}
}
// 创建一个动物类
class Animal{
late String name;
late String info;
Animal(this.name,this.info){
print("传入的动物是:$name ,种类是:$info");
}
}在上面类的上一级目录创建一个名为Factory_Constuctor.dart的文件,并写入下面代码,主要是实现类的调用。
import 'lib/lei.dart';
void main(List<String> args) {
// Person p = new Person(123,456);
Person p = new Person.info();
int a1 = p.a;
print("a为:$a1");
Animal animal = new Animal("小狗", "泰迪");
print(animal.name);
}这是命名构造函数
a为:10
传入的动物是:小狗 ,种类是:泰迪
小狗- 使用`import ''方式导入模块。
构造器(构造函数)
默认构造函数
- 与类同名的函数称为构造函数,在实例化时,自动被调用。
- 构造函数中设置形参称为有参构造函数,反之为无参构造函数。
- this指向的是类中的属性,目的是为了避免混淆。
// 构造函数
class Point{
// 定义类属性
num x=0,y=0;
// 声明普通构造函数,在创建对象时,就会自动执行构造函数
Point(num x, num y){ // 构造函数与类同名,并设置为有参构造函数
print("这是构造函数");
// 打印
print("参数值$x $y");
// 为了避免有歧义,使用this指向类中属性
this.x=10; //指向第4行的x,并改变x的值为10
this.y=20; //指向第4行的y,并改变y的值为20
}
}
void main(List<String> args) {
Point p = new Point(40,30); // 创建对象,并给构造函数传递参数
print("属性值:");
print(p.x); // 打印属性x的值
print(p.y);
}这是构造函数
参数值40 30
属性值:
10
20- 构造函数简写
class Point{
// 定义类属性
num x=0,y=0;
// 简写构造函数
Point(this.x, this.y); // 简写构造函数,需要加分号结尾。
}
void main(List<String> args) {
Point p = new Point(40,30); // 创建对象,并给构造函数传递参数
print("属性值:");
print(p.x); // 打印属性x的值
print(p.y);
}属性值:
40
30命名构造函数
- 默认构造函数
- 与类名同名的函数,在实例化时,自动被调用。
- 命名构造函数
- 在类中使用命名构造函器(类名.函数名)实现多个构造器,可以提供额外的清晰度。
class Point{
// 定义类属性
num x=0, y=0;
// 简写构造函数
Point(this.x,this.y);
// 命名构造函数
Point.origin(){ // origin-原始的
x = 0;
y = 0;
}
Point.fromJson({x:0,y:0}){
this.x = x;
this.y = y;
}
}
void main(List<String> args) {
// 默认坐标
Point p1 = new Point.origin();
print(p1.x);
// 手动设置坐标
Point p2 = new Point.fromJson(x: 20,y: 30);
print(p2.x);
}0
20常量构造函数
- 如果类生产的对象不会改变,可以通过常量构造函数使这些对象成为编译时常量。
- 常量编译快,因为常量不改变。
- 创建对象时可以不使用
new关键字。
class Point{
num x=0;
num y=0;
// 构造函数简写
Point(this.x,this.y);
}
class ImmutablePoint{
// 属性必须通过 final 声明
final num x;
final num y;
// 常量构造函数,必须通过 const 声明,并且常量声明的函数不能有函数体
const ImmutablePoint(this.x,this.y);
}
void main(List<String> args) {
var p1 = new Point(1, 3);
var p2 = new Point(1, 3);
print(p1 == p2);
// 常量构造函数,可以当做普通构造函数使用
var p3 = new ImmutablePoint(3,4);
var p4 = new ImmutablePoint(3,4);
print(p3 ==p4);
// 声明不可变对象,必须通过 const 关键字,而new出来的对象是指向不同的地址,所以不相等
var p5 = const ImmutablePoint(3,4);
var p6 = const ImmutablePoint(3,4);
print(p5 ==p6); // true
// 创建对象可以不用 new 关键字进行实现
var p7 = ImmutablePoint(3,4);
var p8 = ImmutablePoint(3,4);
print(p3 ==p4); // false
}私有与公有
分为私有属性和私有方法,就是在属性名或者方法名前面加一个短下划线_,例如:_name 和_Animal()方法就是被定义为私有的属性和方法。
- 私有属性只能在当前类中访问。
在lib目录下创建一个名为private.dart的文件,里面写一下代码:
// 创建一个动物类
class Animal{
late String _name; // 定义私有属性
late String info;
// ignore: unused_element
_Animal(_name,info){
print("传入的动物是:$this._name ,种类是:$info");
}
int _aaa(){ // 定义私有方法
return 100;
}
}
// 创建一个人类
// 创建一个人类
class Person{
late String name;
late String info;
Person(this.name,this.info){
print(this.name);
print(this.info);
}
}在privaDemo.dart文件中调用。
import 'lib/private.dart';
void main(List<String> args) {
Animal animal = new Animal("晓白", "牧羊犬");
// var aa = animal._aaa(); // 不能调用私有方法
// String name = animal._name; // 不能访问私有属性
print(animal.info);
Person p = new Person("张三","法外狂徒");
print("name为:${p.name}");
}传入的动物是:晓白 ,种类是:牧羊犬
牧羊犬
张三
法外狂徒
name为:张三工厂构造函数
通过 factory 声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例。
getter 与 setter
- get方法,注意方法名之后不加小括号。
- set方法,注意set方法需要加小括号。
class Rect{
late num _height;
late num _width;
Rect(this._height,this._width);
// get方法,注意方法名之后不加小括号
get getarea{
return this._height* this._height;
}
// set方法,注意set方法需要加小括号
set setHeight(value){
this._height = value;
}
}
void main(List<String> args) {
Rect rect = new Rect(10, 20);
// 得到getarea值
print("矩形面积为:${rect.getarea}");
// 调用set方法为height设置值
rect.setHeight=30;
print("面积为:${rect.getarea}");
}矩形面积为:100
面积为:900类的初始化列表
- 先赋值,在进行实例化构造函数。
- 将需要赋值的属性写在构造函数小括号后面。
class Rect{
late num height;
late num width;
// 初始化列表
Rect():height=3,width=20{
print("height为:${this.height},width为:${this.width}");
}
}
void main(List<String> args) {
// 创建对象
Rect rect = new Rect();
}height为:3,width为:20静态成员
- 使用
static关键字来实现类级别的变量和函数。 - 静态方法不能访问非静态成员,非静态方法可以访问静态成员。
- 静态方法和静态属性不能由对象进行访问,只能由类直接访问。
import 'dart:ffi';
class Person{
static String name = "张三"; // 定义静态属性
int age = 18; // 定义非静态方法
// 定义静态方法
static void show(){
print("我的名字叫:${name}");
}
void printInfo(){
print("${name}的信息");
print("年龄为:${this.age}");
// 调用静态方法
show();
}
static void printUserInfo(){
print(name); // 访问静态属性
show(); // 调用静态方法
// print(age); // 静态方法无法范文非静态属性
// this.printInfo(); // 静态方法无法访问非静态方法
// printInfo(); // 静态方法无法访问非静态方法
}
}
void main(List<String> args) {
// Person person = new Person(); // 创建对象
// person.show(); // 被修饰的静态方法不能由创建的对象进行访问
// 由类名进行访问
print(Person.name);
Person.show();
// 非静态方法与非静态属性的使用
Person person = new Person();
person.printInfo();
print(person.age);
// 调用静态方法
Person.printUserInfo();
}张三
我的名字叫:张三
张三的信息
年龄为:18
我的名字叫:张三
18
张三
我的名字叫:张三继承
- 子类使用
extends关键字来继承父类。 - 子类会继承父类里面可见的属性和方法,但是不会继承构造函数。
- 子类能复写父类的方法 getter 和setter。
class Person{
String name ="张三";
num age = 20;
void printInfo(){
print("姓名:${this.name},年龄:${this.age}");
}
}
// 创建一个男人类,并继承人类
class Man extends Person{
}
void main(List<String> args) {
// 创建一个男人对象
Man man = new Man();
print(man.name); // 调用人类的name
man.printInfo(); // 调用父类的方法
}张三
姓名:张三,年龄:20super关键字的使用
- 重写父类构造函数,为父类构造函数进行传参。
- 因为父类里面的属性没有赋值,而子类又需要调用父类的属性,只有通过构造函数进行赋值。
- 在复写父类的方法时,记得加上
@override关键词。
class Person{
late String name;
late num age;
// 构造函数
Person(this.name,this.age);
void printInfo(){
print("Person类");
print("姓名:${this.name},年龄:${this.age}");
}
}
// 创建一个男人类,并继承人类
class Man extends Person{
// 定义子类的属性
late String sex;
// 重写父类构造函数
Man(String name, num age, String sex) : super(name, age){ // 实例化构造函数的时候,将子类的name与age传递给父类的构造函数
this.sex =sex; // 将子类的构造函数里的sex赋值给子类sex属性
}
// 复写父类方法
@override
void printInfo(){
print("man类");
print("姓名:${this.name},年龄:${this.age},性别:${this.sex}");
}
// 定义子类的方法
void run(){
print("儿子类子跑");
}
}
void main(List<String> args) {
// 创建父类对象
Person person = new Person("张三",18);
person.printInfo();
// Person person1 = new Person("李四",56);
// person1.printInfo();
// 创建子类对象
Man man =new Man("张大娃", 32,"男");
man.printInfo(); // 通过构造函数,找到父类的构造函数,使用父类的方法进行打印。
man.run(); // 子类调用子类的方法
}Person类
姓名:张三,年龄:18
man类
姓名:张大娃,年龄:32,性别:男
儿子类子跑使用super为命名构造函数传参。
class Person{
late String name;
late num age;
// 命名构造函数
Person.xxx(this.name,this.age);
// 创建一个男人类,并继承人类
class Man extends Person{
// 定义子类的属性
late String sex;
// 重写父类构造函数
Man(String name, num age, String sex) : super.xxx(name, age){ // 实例化命名构造函数的时候,将子类的name与age传递给父类的构造函数
this.sex =sex; // 将子类的构造函数里的sex赋值给子类sex属性
}
// 复写父类方法
@override
void printInfo(){
print("man类");
print("姓名:${this.name},年龄:${this.age},性别:${this.sex}");
}
void main(List<String> args) {
Person person = new Person.xxx("张三",18); // 命名构造函数传参
person.printInfo();
Man man =new Man("张大娃", 32,"男");
man.printInfo(); // 通过构造函数,找到父类的构造函数,使用父类的方法进行打印。
man.run(); // 子类调用子类的方法
}Person类
姓名:张三,年龄:18
man类
姓名:张大娃,年龄:32,性别:男- 子类调用父类方法,在子类的方法名前面加上一个
supper关键字,例如:supper.run(),调用父类的run()方法。 - 子类中使用父类的属性时,可以使用
this关键词进行调用。
抽象类
- 抽象类主要用于定义标准。
- 抽象类通过
abstract关键字来定义。 - Dart中的抽象方法不能用
abstract声明,Dart中没有方法体的方法我们称为抽象方法。 - 如果子类继承抽象类必须得实现里面的抽象方法。
- 如果把抽象类当作接口实现的话。必须实现抽象类里面定义的所有属性和方法。
- 抽象类不能被实例化,只有继承他的子类可以实例化。
- extends 抽象类和 implements 的区别:
- 如果复用抽象类里面的方法,并且要用抽象方法约束子类的话,我们要用extends继承抽象类。
- 如果只是把抽象类当作标准的话,我们需要用implements实现抽象类。
// 定义抽象类
abstract class Animal{
eat(); // 抽象方法
run();
// 在抽象类中定义,该方法可以有方法体
printInfo(){
print("我来自抽象类");
}
}
// 子类继承父类必须实现父类中的所有方法
class Dog extends Animal{
@override
eat() {
print("小狗在啃骨头");
}
@override
run() {
print("小狗再跑");
}
}
// 子类继承父类必须实现父类中的所有方法
class Cat extends Animal{
@override
eat() {
print("小猫在吃饭");
}
@override
run() {
print("小猫在跑");
}
}
void main(List<String> args) {
Dog dog = new Dog();
dog.eat();
dog.printInfo(); // 调用抽象类的方法
Cat cat = new Cat();
cat.eat();
cat.printInfo(); // 调用抽象类的方法
}小狗在啃骨头
我来自抽象类
小猫在吃饭
我来自抽象类多态
- 多态就是父类定义的一个方法不去实现,让他的子类去实现,每个子类有不同的表现。
- 子类的实例赋值给父类。
// 定义抽象类
abstract class Animal{
eat(); // 抽象方法
}
// 子类继承父类必须实现父类中的所有方法
class Dog extends Animal{
@override
eat() {
print("小狗在啃骨头");
}
//
run(){
print("小狗正在跑");
}
}
// 子类继承父类必须实现父类中的所有方法
class Cat extends Animal{
@override
eat() {
print("小猫在吃饭");
}
//
run(){
print("小狗正在跑");
}
}
void main(List<String> args) {
// 子类的一个实例赋值给父类的应用,也就是所在下面创建的对象就属于父类,而run方法时子类中定义的,所以父类无法调用子类的run方法。
Animal dog = new Dog();
dog.eat();
// dog.run(); // 无法调用run方法
Animal cat = new Cat();
cat.eat();
// cat.run(); // 无法调用run方法,父类中没有run 方法
}小狗在啃骨头
小狗正在跑
小猫在吃饭接口
- Dart的接口没有
interface关键字定义接口,普通类或抽象类都可以作为接口被实现。 - 使用
implement关键字进行实现。 - 如果实现的类是普通类,会将普通类和抽象类中的属性的方法全部重写一边。
- 抽象类可以定义抽象方法,普通类不可以,普通类不可以,所以一般如果要实现象Java接口那样的方式,一般会使用抽象类。
- 建议使用抽象类定义接口。
- 接口就是约定、规范。
// 定义接口
abstract class Person{
late String name;
eat();
run();
info(String str);
}
// 继承Person接口
class Man implements Person{
@override
late String name;
@override
eat() {
print("男人在吃饭");
}
@override
info(String str) {
print("${str}的信息");
}
@override
run() {
print("男人在奔跑");
}
Man(String str);
}
// 继承Person接口
class Women implements Person{
@override
late String name;
@override
eat() {
print("女人在吃饭");
}
@override
info(name) {
print("${name}的信息");
}
@override
run() {
print("女人在奔跑");
}
// Women(this.name);
}
void main(List<String> args) {
// 创建man对象
Man man = new Man("张三");
man.info("张三");
// 创建women对象
Women women = new Women();
women.info("张如玉");
women.run();
}可以将这些接口、类、main进行分离,分别放在不同的Dart文件中,如果要导入这些模块,需要使用improt关键字进行导入。
多接口 mixins新特性
- mixins的中文意思是混入,就是在类中混入其他功能。
- 在Dart中可以使用
mixins实现类似多继承的功能。 - 作为
mixins的类只能继承自Object,不能继承其他类。 - 作为
mixins的类不能有构造函数。 - 一个类可以
mixins多个mixins类。 -
mixins绝不是继承,也不是接口,而是一种全新的特性。
小结:
多继承:
使用with后面的类:
被继承的类不能继承其他类
被继承的类中不能有构造函数
with
class X with a,b{
...
}
也可以
class X extends c with a,b{
...
}
抽象类:
抽象类不能实例化,继承必须实现内部抽象方法和属性
抽象类可以继承extends(复用其中普通方法),可以实现implements(当模板)
抽象类中的方法不加abstract
abstract class x{
int a;
int b;
void f(); 抽象方法
void ff(){...}; 普通方法
}
继承该抽象类的类,只用实现抽象方法,普通方法和属性不用重写
多态:父类引用子类,父类的方法引用子类的方法,只能调用父类中存在的方法,不能调用子类中父类没有的方法
Animal c=new Dog(); c只能调用Animal中的方法,且引用子类Dog中的相同方法
接口:
使用abstract定义抽象类为接口,操作和抽象类一样
抽象类的所有属性和函数都必须重写
abstract class x{
int a;
int b;
void f(); 抽象方法
void ff(){...}; 普通方法
}
class c implements x{
int a;
int b;
void f(){}
void ff(){}
}
多接口:
class c implements a,b{...}泛型
- 泛型就是解决 类、 接口、 方法的复用性、以及对不特定数据类型的支持(类型校验)。
- 不指定类型就是放弃了类型校验。想传入什么类型就可以传入什么类型。
T getValue<T>(T value){..方法体..return..}- 第一个T表示返回类型,第二个T表示函数类型,第三个T表示参数类型。
泛型方法
// 定义泛型方法,一般使用大写 T 表示
T getValue<T>(T value){
return value;
}
void main(List<String> args) {
// 传入int类型参数
var d = getValue(123);
print(d);
// 传入string类型参数并指定类型。
var str =getValue<String>("张三");
print(str);
}123
张三泛型类
- 泛型就是一种通用的类型格式,一般用在集合中,用来指定该集合中应该存储的对象格式。
- 泛型一般使用大写的单个字符来表示,通常来说是E, T, S, K 和 V等。
- 巧妙的使用泛型还能够减少我们的代码量,因为泛型可以代表一类通用的类型。
class Mylist<T>{ // 定义一个泛型类
List list = <T>[]; // 定义一个泛型列表
// 定义一个泛型方法,负责向列表中添加数据
void add(T value){
this.list.add(value);
}
// 返回列表
List getList(){
return list;
}
}
void main(List<String> args) {
// 限定为String类型的列表
Mylist l2 = Mylist<String>();
l2.add("张三"); // 添加一个string参数
l2.add("李四");
// l2.add(123); // 在创建对象时限定为String类型,只能传入String数据
print(l2.getList()); // 打印列表
// 限定为int类型的列表
Mylist l3 = Mylist<int>();
l3.add(123);
l3.add(456);
print(l3.getList());
}[1, 张三, false]。。。。。。。。
有时间再更新
。。。。。。。。
















