语言对比学习-Dart

语言对比学习-Dart

Dart介绍

Dart是由Google开发的计算机编程语言,它可以被用于web、服务器、移动应用 和物联网等领域的开发。
Dart诞生于2011年,号称要取代JavaScript。但是过去的几年中一直不温不火。直到Flutter的出现现在被人们重新重视。
要学Flutter的话我们必须首先得会Dart。
官网:https://dart.dev/

在 Google 内部孵化了移动开发框架 Flutter,弯道超车进入了移动开发的领域;而在 Google 未来的操作系统 Fuchsia 中, Dart 更是被指定为官方的开发语言。

Dart特性

1、Dart VM

Dart VM 是一个执行 Dart 语言的组件集合,包括但不限于以下组件:

运行系统

对象模型
垃圾收集
快照
native 代码核心库

开发体验优化组件

debug调试
性能分析
热重载
JIT(Just-in-Time)和 AOT (Ahead of time) 编译管道。

解释器

ARM指令模拟器

2、JIT与AOT

总结来讲,在开发期使用 JIT 编译,可以缩短产品的开发周期。Flutter 最受欢迎的功能之一热重载,正是基于此特性。而在发布期使用 AOT,就不需要像 React Native 那样在跨平台 JavaScript 代码和原生 Android、iOS 代码之间建立低效的方法调用映射关系。所以说, Dart 具有运行速度快、执行性能好的特点。

那么,如何区分一门语言究竟是 AOT 还是 JIT 呢?通常来说,看代码在执行前是否需要编译即可。如果需要编译,通常属于 AOT;如果不需要,则属于 JIT。

AOT 的典型代表是 C/C++,它们必须在执行前编译成机器码;而 JIT 的代表,则包括了如 JavaScript、Python 等几乎所有的脚本语言。

3、内存分配与垃圾回收

Dart VM 的内存分配策略比较简单,创建对象时只需要在堆上移动指针,内存增长始终是线性的,省去了查找可用内存的过程。

在 Dart中,并发是通过 Isolate 实现的。Isolate 是类似于线程但不共享内存,独立运行的 worker 。这样的机制,就可以让 Dart 实现无锁的快速分配。

Dart 的垃圾回收,则是采用了多生代算法。新生代在回收内存时采用“半空间”机制,触发垃圾回收时,Dart 会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存。回收过程中,Dart 只需要操作少量的“活跃”对象,没有引用的大量“死亡”对象则被忽略,这样的回收机制很适合 Flutter 框架中大量 Widget 销毁重建的场景。

4、单线程模型

支持并发执行线程的高级语言(比如,C++、Java、Objective-C),大都以抢占式的方式切换线程,即:每个线程都会被分配一个固定的时间片来执行,超过了时间片后线程上下文将被抢占后切换。如果这时正在更新线程间的共享资源,抢占后就可能导致数据不同步的问题。

解决这一问题的典型方法是,使用锁来保护共享资源,但锁本身又可能会带来性能损耗,甚至出现死锁等更严重的问题。

这时,Dart 是单线程模型的优势就体现出来了,因为它天然不存在资源竞争和状态同步的问题。这就意味着,一旦某个函数开始执行,就将执行到这个函数结束,而不会被其他 Dart 代码打断。

所以,Dart 中并没有线程,只有 Isolate (隔离区)。Isolates 之间不会共享内存,就像几个运行在不同进程中的 worker,通过事件循环(Event Looper)在事件队列(Event Queue)上传递消息通信。

5、无需单独的声明式布局语言

在 Flutter 中,界面布局直接通过 Dart 编码来定义
开发过程也不需要可视化界面构建器,因为热重载可以让我们立即在手机上看到运行效果

一、Hello World

1、环境搭建

2、Hello World

Dart 语言 以 .dart 为文件后缀

main(){
  print('hello dart');
}

二、Dart基础

能够放在变量中的所有内容都是对象,每个对象都是一个类的实例。甚至于数字、函数和null值都是对象,并且所有对象都继承自Object类。

如果一个变量没有初始化值,那它的默认值就为null。

1、数据类型

跟常用的其他语言不同,Dart 没有 byte、char 和 float。
int、double 都是 64 位

1.1、数字

num
num 是数字类型 , 其有两个子类 , int 和 double 类型

int
必须是整型
int age = 18;

double
既可以是整型,也可以是浮点型

1.2、字符串

String
单引号,双引号,三引号(可以写多行)
String name = “bruce”;

// 字符串拼接
print(“$str1$str2”)或者print(str1 + str2) 

Dart 里的 String 跟 Java 中的一样,是不可变对象;
不同的是,检测两个 String 的内容是否一样事,我们使用 == 进行比较;
如果要测试两个对象是否是同一个对象(indentity test),使用 identical 函数。

1.3、布尔

bool

1.4、var

dart是一个强大的脚本类语言,可以不预先定义变量类型,自动会类型推导
dart中定义变量可以通过var关键字可以通过类型来申明变量
不需要任何类型,可以使用特殊类型dynamic标识。

var str = "你好,dart";
String str2 = "str2";
// 字符串拼接
String str3 = "$str2";

var a = 110;
int a = 111;

//double既可以是整形也可以是浮点型
double b = 12.5;
double c = 12;

bool flag1 = false;

final 和 const
在dart 中 常量可以用 const 和 final 关键字修饰:
const值不变 一开始就得赋值
final 可以开始不赋值 只能赋一次 ; 而final不仅有const的编译时常量的特性,
最重要的它是运行时常量,并且final是惰性初始化,即在运行时第一次使用前才初始化
永远不改变的量,请使用final或const修饰它,而不是使用var或其他变量类型。

Object 和 dynamic 都使得我们可以接收任意类型的参数,但两者的区别非常的大。
使用 Object 时,我们只是在说接受任意类型,我们需要的是一个 Object。类型系统会保证其类型安全。
使用 dynamic 则是告诉编译器,我们知道自己在做什么,不用做类型检测。当我们调用一个不存在的方法时,会执行 noSuchMethod() 方法,默认情况下(在 Object 里实现)它会抛出 NoSuchMethodError。

1.5、类型转换
  //Number与String类型之间的转换
  String str = "110";
  var myNum = int.parse(str);
  print(myNum is int);
  
  //double.parse
  //Number类型转化为String类型toString() 
  
  console: true

2、运算符

2.1、算数运行符

/
%
~/ (返回一个整数值的除法,不是四舍五入)

2.2、关系运算符

==!+ < > <= >=

2.3、逻辑运算符

!
&&
||

2.4、赋值运算符

=
??=
+=
-=
*=
/=
%=
~/=

??=:int a = 10;a??=23;(首先判断a是否为null,如果是null,则23赋值给a,如果不为空,不变)

2.5、未使用过的运算符通过代码来做个介绍

?.的使用

//定义类
class Person {
  var name;
  Person(this.name);
}

// 调用
Person p;
var name = p?.name; //先判断p是否为null,如果是,则name为null;如果否,则返回p.name值
print("name = $name");

// 输出结果
name = null

~/的使用

// 代码语句
var num = 10;
var result = num ~/ 3; //得出一个小于等于(num/3)的最大整数
print("result = $result");

// 输出结果
result = 3

as的使用,as用来做类型转化

// 类定义
class Banana {
  var weight;
  Banana(this.weight);
}

class Apple {
  var weight;
  Apple(this.weight);
}

// 调用
dynamic b = Banana(20);
(b as Banana).weight = 20; // 正常执行
print("b.weight = ${(b as Banana).weight}");
(b as Apple).weight = 30; // 类型转换错误,运行报错
print("b.weight = ${(b as	Apple).weight}");

//输出结果
b.weight = 20
Uncaught exception:
CastError: Instance of 'Banana': type 'Banana' is not a subtype of type 'Apple'

is的使用

// 函数和类代码定义
getFruit() => Banana(20); // 获取一个水果对象

class Banana {
  var weight;
  Banana(this.weight);
}

class Apple {
  var color;
  Apple(this.color);
}

// 调用
var b = getFruit();
if(b is Apple) { //判断对象是否为Apple类
  print("The fruit is an apple");
} else if(b is Banana) { //判断水果是否为Banana类
  print("The fruit is a banana");
}

// 输出结果
The fruit is a banana

??的使用

// 操作代码块
String name;
String nickName = name ?? "Nick"; //如果name不为null,则nickName值为name的值,否则值为Nick
print("nickName = $nickName");
  
name = "Bruce";
nickName = name ?? "Nick"; //如果name不为null,则nickName值为name的值,否则值为Nick
print("nickName = $nickName");
  
// 输出结果
nickName = Nick
nickName = Bruce 

…的使用,级联操作允许对同一个对象进行一系列操作。

// 类定义
class Banana {
  var weight;
  var color;
  Banana(this.weight, this.color);
  
  void showWeight() {
    print("weight = $weight");
  }
  
  void showColor() {
    print("color = $color");
  }
}

// 调用
Banana(20, 'yellow')
    ..showWeight()
    ..showColor();
    
// 输出结果
weight = 20
color = yellow

3、条件表达式

if else switch case

4、循环语句

for while do…while
三目运算符、??运算符
break continue
for循环和java一样

5、集合

5.1、List
  // list初始化
  List myList = ["香蕉", "苹果", "西瓜"];
  print(myList[0]);

  var myListVar = [];
  myListVar.add("111");
  myListVar.add("222");
  print(myListVar);
  
  // var list = List<int>();
  ar list4 = const[1, 2];
// list4 指向的是一个常量,我们不能给它添加元素(不能修改它)
  
// Dart 同样提供了 for-in 循环。
// 语言设计时就考虑到了这个需求,in 在 Dart 里是一个关键字
var list6 = [1, 3, 5, 7];
for (var e in list6) {
  print(e);
}
5.2、Set
  var s = new Set();
  s.add("校长");
  s.add("老师");
  print(s);
5.3、Map
  var map1 = new Map();
  map1["name"] = "小红";
  print(map1);

6、类

Dart所有的东西都是对象,所有的对象都继承自Object类

在 Dart 2 里,创建对象时可以省略 new 关键字,也推荐省略 new

6.1、构造函数

Dart的构造函数同普通函数一样,可以定义无参和有参,命名参数和位置参数,可选参数和给可选参数设置默认值等。Dart的构造函数有以下几个特点:

可以定义命名构造函数
可以在函数体运行之前初始化实例变量
子类不从父类继承构造函数,定义没有构造函数的子类只有无参无名称的构造函数
子类定义构造函数时默认继承父类无参构造函数,也可继承指定有参数的构造函数;

命名构造函数和函数体运行前初始化实例变量

// 类定义
class Tree {
  var desc;
  
  // 命名构造函数
  Tree.init() {
    desc = "this is a seed";
  }
  
  // 函数体运行之前初始化实例变量
  Tree(var des) : desc = des;
}

// 构造函数调用
Tree t = Tree.init();
print("${t.desc}");

Tree t1 = Tree("this is a tree");
print("${t1.desc}");

// 输出结果
this is a seed
this is a tree

构造函数继承

// 类定义
class Fruit {
  Fruit() {
    print("this is Fruit constructor with no param");
  }
  
  Fruit.desc(var desc) {
    print("$desc in Fruit");
  }
}

class Apple extends Fruit {
  Apple():super() {
    print("this is Apple constructor with no param");
  }
  
  // 默认继承无参构造函数
  Apple.desc(var desc) {
    print('$desc in Apple');
  }
}

// 构造函数调用
Apple();
Apple.desc("say hello");
  
// 输出结果
this is Fruit constructor with no param
this is Apple constructor with no param
this is Fruit constructor with no param
say hello in Apple

initializer list 会在构造函数的函数体运行前执行。

Dart 具有垃圾收集功能,对象的使用跟 Java 里几乎是一样的

6.2、类中的私有方法和私有属性

通过下划线表示私有
Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合
但是我们可以使用_把一个属性或者方法定义成私有。
Dart中的私有属性必须在单独的模块文件,并且在前面加上_下划线,通过共有方法去访问私有属性和私有方法。

6.3、类的getter和setter修饰符的用法?
6.4、类的初始化列表?

通过:冒号表示,多个初始化通过,逗号分隔

6.5、类的静态成员和方法

使用static关键字来实现类级别的变量和函数
静态方法不能访问非静态成员,非静态方法可以访问静态成员

6.6、类的继承

extends
super
override

6.7、mixins 实现多继承

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:
1、作为mixins的类只能继承自Object,不能继承其他类
2、作为mixins的类不能有构造函数
3、一个类可以mixins多个mixins类
4、mixins绝不是继承,也不是接口,而是一种全新的特性

dart中使用mixins实现多继承,使用with关键字
当继承的多个类中有同样的方法时,谁排在最后则调用谁的函数。
作为mixins的类只能继承自Object,不能继承其他类
作为mixins的类不能有构造函数

// 类定义
class LogUtil {
  void log() {
    print("this is a log");
  }
}

class Fruit {
  Fruit() {
    print("this is Fruit constructor with no param");
  }
}

class Apple extends Fruit with LogUtil {
  Apple():super() {
    print("this is Apple constructor with no param");
  }
}

// 调用
Apple a = Apple();
a.log(); //可执行从LogUtil继承过来的方法

// 输出结果
this is Fruit constructor with no param
this is Apple constructor with no param
this is a log

6.8、对象操作符

? 条件运算符 (了解)
as 类型转换
is 类型判断
… 级联操作 (连缀) (记住)
也就是当我们需要对一个对象执行一系列操作时,级联是非常有用的,方便我们操作对象,节省代码量

    print(new Address()
    ..street = '北京市'
    ..number = '12'
    ..name = '西城区');

7、抽象类

abstract

8、接口

首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现

同样使用implements关键字进行实现。
但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。

而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
建议使用抽象类定义接口。

Dart中使用抽象类代替了接口,实现抽象类,就必须实现所有的抽象方法和属性

9、函数/方法

9.1、方法参数

基本参数
可选参数
默认参数

9.2、函数

箭头函数
内部语句后面不需要加分号,其他的每个语句后面必须要加分号

  List list = ["小红", "校长", "feig"];
  //注意箭头函数只能有一条语句
  list.forEach((value) => print("value=$value"));

匿名函数
函数作为参数:Dart中的函数可以作为另一个函数的参数
嵌套函数:Dart支持嵌套函数,也就是函数中可以定义函数

10、闭包

1.全局变量特点:全局变量常驻内存、全局变量污染全局
2.局部变量的特点:不常驻内存会被垃圾机制回收,不会污染全局

想实现的功能:
1.常驻内存
2.不污染内存
产生了闭包,闭包可以解决这个问题
闭包:函数嵌套函数,内部函数会调用外部函数的变量或参数,
变量或参数不会被系统回收(不会释放内存)
闭包的写法:函数嵌套函数,并return 里面的函数,这样就形成了闭包

  fun() {
    var a = 123;
    return () {
      a++;
      print(a);
    };
  }

  var b = fun();
  b(); //124
  b(); //125
  b(); //126

11、泛型

Dart同Java一样,也支持泛型

泛型类
在构造方法中使用泛型
泛型方法

12、异步

12.1、async await

只有async方法才能使用await关键字调用方法
如果调用别的async方法必须使用await关键字

async是让方法变成异步。
await是等待异步方法执行完成。

12.2、Future
import 'dart:io';
void foo() {  
var file = File('path-to-your-file');
file.exists() 
.then((exists) => print('file ${exists ? 'exists' : 'not exists'}'))      
.catchError((e) => print(e));
}
12.3、Stream

13、Dart中的lib介绍

Dart中的库主要有三种:

13.1、自定义的库
          import 'lib/xxx.dart';
    2、系统内置库       
          import 'dart:math';    
          import 'dart:io'; 
          import 'dart:convert';
    3、Pub包管理系统中的库  
        https://pub.dev/packages
        https://pub.flutter-io.cn/packages
        https://pub.dartlang.org/flutter/
 
        1、需要在自己想项目根目录新建一个pubspec.yaml
        2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
        3、然后运行 pub get 获取包下载到本地  
        4、项目中引入库 import 'package:http/http.dart' as http; 看文档使用
13.2、类库冲突解决

当引入两个库中有相同名称标识符的时候,如果是java通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。如下例子所示:

import 'package:lib1/lib1.dart';
    import 'package:lib2/lib2.dart' as lib2;
 
 
    Element element1 = new Element();           // Uses Element from lib1.
    lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.

14、异常

Dart的异常捕获也是使用try-catch语法,不过与java等语言稍有不同

// 定义一个抛出异常的函数
void handleOperator() => throw Exception("this operator exception!");

// 函数调用
try {
  handleOperator();
} on Exception catch(e) {
  print(e);
} finally { // finally语句可选
  print("finally");
}

// 输出结果
Exception: this operator exception!
finally

15、元数据?

学习资料

https://www.dartlang.org
https://dart.dev/guides/language/language-tour
http://dart.goodev.org/guides/language/language-tour

上一篇:retrofit上传图片,安卓工程师跳槽经验分享,最强技术实现


下一篇:面试时被问到Flutter/Dart的HashMap怎么办?