《Flutter实战》第二版学习记录 https://book.flutterchina.club/
最近学习Flutter,发现其使用的Dart语言,有些方面很像Java,有些方面又很像Kotlin,所以整理下目前发现的区别点,一方面方便自己记忆,另一方面也希望可以给尚未接触过Flutter小伙伴们提供一些帮助。(本文仅从Dart语言使用角度对比Java & Kotlin。)
Dart中,只有三种基本数据类型,数字型(num
),布尔型(bool
),字符串类型(String
)。容器类型如List ,Map,是否属于基本数据类型,这里暂不讨论,毕竟使用也很简单。
类型 | Dart | Java | Kotlin |
---|---|---|---|
布尔 | bool | boolean | Boolean |
数字 | num (int / double) | int / double / long / char /byte ... | Int / Double /Long / Char / Byte... |
字符串 | String | String | String |
-
num
在Dart 中为抽象类,具有int
及double
两个实现类,使用num
为类型定义变量时,会进行变量类型推断,推断为对应的实现类(int
/double
)。///其中需要注意,Dart中num 同样可以作为数据类型使用,如: num a = 10; (整数型) num b = 10.0; (浮点型) int c = 10; (整数型) double d = 10.00; (浮点型)
-
int 类型不仅可以表示整形数字,还代表byte 及 char类型数据,具体使用方式如下:
///byte 类型 int x = 65; print(x.toRadixString(2));// 输出 1000001 ///char 类型 List<int> codes = [65, 66]; for(var element in codes) { print(String.fromCharCode(element); //输出 AB }
-
先看下Dart中字符串的定义,大概与Java 和 Kotlin相同:
字符串定义: ///单引号定义字符串 String e = 'hello world'; String g = '''hello world'''; ///双引号定义字符串 String f = "hello world"; String h = """hello world""";
-
其中使用三引号
'''
与"""
时,会跟随文本换行,而双引号与单引号""
与''
不会,单引号主动换行需要借助\n
换行符。单引号定义的字符串中可以包含双引号,双引号定义的字符串中可以包含单引号, 同类引号中无法包含同类引号,如:错误使用: String a = "----"hello world"----"; String b = '----'hello world'----'; 正确使用: String a = '----"hello world"----'; String b = "----'hello world'----";
-
Dart 支持 Kotlin 字符串拼接方式:
String name = "Child"; String s = "$name, hello world, ${name}"
Dart的语法与Java基本是相同的,只不过在细节上有些差异,Dart在Java基础上,进行了优化。Dart在Java基础上,进行了优化,使其更加简洁,方便。
-
Dart中类构造函数写法有很多种,既可以使用与Java完全一样的写法,也可以使用Dart特有写法,具体写入如下:
Class TestA { int a = 0; int b = 0; ///与Java相同的基本写法 TestA(int a, int b) { this.a = a; this.b = b; } ///Dart 特有构造写法, ///方式1: TestA(this.a, this.b); ///方式2: TestA(int x, int y) : this.a = x, this.b = y; ///方式3:命名构造,与Kotlin中的扩展函数类似,但功能完全不同。 TestA.instance(this.a, this.b); }
个人感觉,为了方便与Java区分,不建议使用与Java相同的构造写法,而且Dart特有的构造写法,更加简洁。
-
对象创建:
///Dart中,可以和Java一样相同,使用new关键字创新对象 TestA a = new TestA(); ///同样也可以使用Kotlin方式一样,创建对象 TestA b = TestA(); var c = TestA();
-
对象属性赋值:
///通用赋值方式: TestA object = TestA(); object.x = 10; object.y = 20; ///Dart特有赋值方式: TestA object = TestA() ..x = 10 ..y = 20;
Dart特有的赋值方式看起来有些奇怪,但是多看看也就习惯了,注意分号(
;
)在赋值结束后添加,赋值过程中不需要加。
-
Dart 中拥有与Kotlin 相同的变量空安全机制。在定义可为空的变量时,需要在变量后加 ?,示例如下:
class Test { String? x = null; void method() { ///当变量可能为null时,添加问号,检查对象是否为null,不为null时,才会实行 print(x?.length); ///类似Java 三元表达式,Kotlin变量判断是否为null,若为null,则赋予对应值。 String y = x ?? 'hello word'; ///当非常非常非常确定,变量不为null时,可以使用!,强制声明变量肯定不为null print(x!.length); } }
-
Dart具有与Kotlin相同的可变参数的功能,只是实现方式有些许不同,示例如下:
class Test() { ///命名参数,required修饰的参数都为必填 void method1({required int a, required int b}) { print('add = ${a + b}'); } ///默认参数,可以为参数赋予默认值,使用时,可以不传入该参数 void method2({required int a, int b = 0}) { print('add = ${a + b}'); } /// 位置参数,其特点是必须按顺序依次进行指定若干入参 void method3(int a, [int b = 1, int c = 0]) { print('param: a = ${a}, b = ${b}, c = ${c}'); } void test() { method1(a: 10, b 10); method2(a: 10); method3(10); method3(10, 20); method3(10, 20, 30); } }
这里将从Dart与Java不同的关键字,讲述不同的关键字对功能及编码方面的影响。
-
Dart的类,方法,变量只有两种访问类型,可访问/不可访问:
-
在类名,方法名,变量名前添加
_
(下划线),即为外部类不可访问;没有_
(下划线)为可访问。 -
没有访问范围控制关键字,public, private, protect。
class TestB { ///公共变量 int a = 10; ///私有变量,仅能在本类中调用 int _b = 20; ///常量定义, 与Kotlin中定义相同 const c = 30; ///相当于Kotlin的 lateinit,延迟初始化变量 late String d; ///公共方法,可以供内部/外部类调用 void method1() { } ///私有方法,只能在本类调用 void _method2() { var object = _TestC(); } //静态方法,与Java使用方式一致,TestB.method3() 调用 static void method3() { } } ///私有类,访问范围在本.dart文件中(在TestB类中可以访问),其他文件中无法访问 class _TestC { }
-
Dart中, 没有
interface
接口关键字的定义,但是有implement
。 -
implement
关键字使用,可以实现所有类:抽象类及普通类,需要实现类中所有定义的变量及方法,如下图所示:implement 实现普通类: class BaseA { int x = 10; void method1() { } } class ImplementA implements BaseA { @override int x = 0; @override void method1() { //TODO } }
implement 实现抽象类: abstract class BaseB { final int a = 0; void method1(); void method2() { } } class ImplementB implement BaseB { @override //TODO int get a => 0; @overide void method1() { //TODO } @override void method2() { //TODO } }
-
与Java & Kotlin相同,一个类可以实现多个(接口)类。
-
接口二义性问题解决:当 C 类实现 A 、B 接口,会强制重写所有方法,成员变量提供
get
方法;即在当前类,方法只具有一种实现,变量值需重新赋值,这样就解决了二义性问题。示例如下:class C implement A, B { @override String str = 'hello world'; @override void go() { //TODO } }
-
含义:
with
&mixin
为Dart实现混入(mixins)的关键字,混入是指将一个类的代码插入到另一个类中,以增强该类的功能,而不需要创建一个新的子类。 -
作用:实现类功能扩展(可以同时混入多个)。比如Java & Kotlin 可以通过内部类的形式,来扩展类功能。
-
与普通类区别:混入类,没有构造方法,无法实例化。
-
与接口区别:接口只定义一类功能接口,没有完整功能实现;混入类需具备完整功能实现。
///混入类定义 mixin Write { final String word = 'hello world'; void write() { print('person can write: $word'); } } ///一般类接入混入类,引入混入类实现功能 class Person with Write { @override String get word => 'hello word! ++'; } class Test { void method() { Person p = Person(); p.write(); } }
混入类功能与接口类似,所以同样存在二义性问题,那么混入类是如何解决二义性问题的呢?
- 如C 以先A ,后B顺序混入两个类,A, B 中都含有一个变量名name的字符串,混入C后,打印字符串name,显示的为后混入B类中name的值。 即混入多个类时,若定义的相同类型&相同名称的变量,值为最后混入的类的值。
- 若变量名相同,但变量类型不同,同时混入会报错。
-
这个功能与Kotlin的扩展方法是类似的,都可以在不修改类文件的前提下,扩展类方法。
-
Kotlin不仅可以添加扩展方法,同时可以添加扩展变量。Dart只可以添加拓展方法。
extension StringUtil on String { bool isNullorEmpty(String? str) { return str == null || str.isEmpty; } }
-
on
关键字用于混入类间,实现类似extends
的关系。即混入类可以通过on
关键字引入其他类的功能。需要注意的是,混入类不仅可以引入混入类,也可以引入普通类与抽象类。例如:mixin D { String d = 'hello word! D'; void run() { print('on keyword --- ${d}') } } mixin E on D { @override set(String value) { d = value; } @override void run() { super.run(); } }
-
on
与extension
配合使用,表示对哪个类进行扩展。
-
switch
关键字与Java中的功能相同,即判断执行分支。其中有一个需要注意的细节,Dart中,对象类型也可以作为分支判断条件。class Test { void method1() { Person p1 = Person(); Person p2 = Person(); Person p3 = Person(); Person p = p1; switch(p) { case p1: //TODO break; case p2: //TODO break; case p3: //TODO break; } } }
-
Java中,判断对象只能为基本数据类型,如下图所示。
-
与Kotlin类似,Dart提供了
set
&get
关键字,实现变量的setter
&getter
功能。示例如下:class Test { void method() { A a = A(); print(' get value : ${a.getValue}'); a.setValue(10); print(' get value : ${a.getValue}'); } } class A { int _value = 0; int get getValue => _value; /// => 是Dart中的省略写法,完整方法如下: int get getValue { return _value; } set setValue(int value) { _value = value; } }
-
定义:函数对象与Kotlin的高阶函数类似,可以理解为函数对象类型的关键字;指定传入参数,执行对应代码块后,返回指定类型的返回值。这也是Dart 比 Java 更靠近万物皆对象的体现。
-
作用:与Kotlin的高阶函数功能一致,定义一类功能的实现规则。示例如下:
typedef Operate = int Function(int, int); class Test { void method() { Operate add = (a, b) { return a + b; } add.call(10, 20) } }
总的来说,Dart语言与Java&Kotlin很多相似的地方,在最开始学习时,记住不同点,编码方面就不会有太多的阻碍。但是从语言设计层面看,Dart与Java&Kotlin还是有很大的区别,等我悟道之后,再和大家细说。 如果有需要完善,或者不认同的地方,欢迎大家留言评论。