在学习Dart
的时候,会遇到一些Java
中没有的概念或者用法,这篇文章总结了Dart
和Java
中一些不一样,但又常常会用到的知识点。html
初始化列表定义在构造函数)
和{
之间,初始化列表的语句之间用,
分割,它的做用有以下几点。java
final
变量赋值咱们但愿类中的final
变量初始值能由外部传入,可是在构造函数中为final
变量赋值是不容许的,例以下面这样:编程
class ConstField {
final value;
ConstField(int y) {
value = y;
}
}
复制代码
此时能够采用Dart
提供的初始化列表的方式:ide
class ConstField {
final value;
ConstField(int input) : value = input;
}
复制代码
只有初始化列表,没有构造函数体的时候,初始化列表最后用;
结尾。函数
class ConstField {
final value;
ConstField(int input) : assert(input > 0), value = input;
}
复制代码
class Parent {
int value;
Parent(int input);
}
class Child extends Parent {
Child(int input) : assert(input > 0), super(input);
}
复制代码
在有初始化列表的状况下,函数调用的前后顺序为:学习
const
构造函数能够保证你的类称为永远不会更改的对象,并使这些对象称为编译时常量:ui
const
构造函数确保全部实例变量都是final
的。class ConstConstructor {
final value;
const ConstConstructor(int input) : value = input;
}
复制代码
this
简化赋值class Subject {
int value;
int value2;
Subject(this.value, this.value2);
log() {
print('value=$value, value2=$value2');
}
}
void main() {
Subject(2,3).log();
}
复制代码
当咱们但愿 只为某些变量赋值,其他的采用初始值 时,在Java
中只能采用定义多个构造函数或者使用builder
模式,在Dart
中采用可选参数列表的方式实现就很简单,调用的时候只须要采用 参数名:值 的形式赋值便可。this
class Subject {
int value;
int value2;
Subject({this.value, this.value2 = 3});
log() {
print('value=$value, value2=$value2');
}
}
void main() {
Subject(value : 2).log();
}
复制代码
get
和set
是专门用来读取和写入对象的属性的方法,每个类的实例变量都有一个隐式的getter
和可能的setter
(final
或者const
的只有getter
)。spa
setter/getter
使得咱们在外部能够像对待普通成员变量进行操做,可是在内部进行额外的处理。.net
set/get
后跟的是成员变量的名字,不能够与其它成员变量重名。
class Person {
String _name;
set name(String value) {
assert(value != null);
_name = value;
}
get name => 'Person name is $_name';
}
void main() {
Person p = Person();
p.name = "tom";
print(p.name);
}
复制代码
factory
用于修饰类的构造函数。
例如,咱们有一个Shape
类,当咱们用factory
修饰:
factory Shapre() { return ...; }
复制代码
再经过Shape()
或者new Shape()
的方式调用该函数时,不会真正地建立Shape
,而是由该构造函数返回一个Shape
或者Shape
的子类。
它至关于为类提供了一个静态的建立方法,该方法的返回值是它自己或它的子类对象,可是外部并不知道这个方法的存在,只须要按照普通建立对象的方式建立便可。
根据这一特色,目前factory
的应用有两类:
Java
中工厂模式的实现能够参考这里,工厂模式,下面咱们Dart
的实现版本。
class Shape {
factory Shape(String shapeType) {
if (shapeType.compareTo('CIRCLE') == 0) {
return Square();
} else {
return Circle();
}
}
void draw() {}
}
class Square implements Shape {
@override
void draw() {
print('Inside Square::draw() method.');
}
}
class Circle implements Shape {
@override
void draw() {
print('Inside Circle::draw() method.');
}
}
void main() {
Shape shape = Shape('CIRCLE');
shape.draw();
}
复制代码
回想一下,在Java
中实现单例模式时,通常会将它的构造方法声明为private
,再定义一个getInstance()
的静态方法来返回单例对象。
而在Dart
中,利用factory
的特性,咱们能够仍然按普通的方式建立对象,可是在多个地方得到的是同一个实例。
class Singleton {
//单例对象。
static Singleton _instance;
//构造函数。
Singleton._internal() {
print("_internal");
}
static Singleton _getInstance() {
//仅在 _instance 为空时才调用。
if (_instance == null) {
_instance = Singleton._internal();
}
return _instance;
}
//调用方法。
void method() {
print("method");
}
//1.经过 new Singleton() 调用。
factory Singleton() => _getInstance();
//2.经过 Singleton.instance 调用。
static Singleton get instance => _getInstance();
}
复制代码
调用方式有以下两种,_instance
都会只建立一次:
Singleton.instance.method();
Singleton().method();
复制代码
在Java
中,能够声明多个构造函数,可是会遇到一个问题,若是有多个构造函数接受的参数个数和类型都相同,那怎么办呢?Dart
的命名参数就解决了这一个问题。
除此以外,Dart
的命名构造函数可使得含义更加直观。
class Point {
int x1;
int y1;
Point({this.x1, this.y1});
Point.coordinate100() {
x1 = 100;
y1 = 100;
}
Point.coordinate50() {
x1 = 50;
y1 = 50;
}
log() {
print('x=$x1, y=$y1');
}
}
void main() {
Point p100 = Point.coordinate100();
p100.log();
Point p50 = Point.coordinate50();
p50.log();
}
复制代码
这里须要注意,当咱们声明了命名构造函数,那么就会 覆盖默认的无参构造函数,这点和声明了普通的有参构造函数是同样的。也就是说,在它子类的构造函数中,须要经过super.xxx
显示地调用父类中的构造函数。
在Dart
中有一些操做符和Java
不一样。
is
或者!is
,相似Java
中的instanceof
。void main() {
int n = 2;
print(n is int);
}
void main() {
double n = 2.20;
var num = n is! int;
print(num);
}
复制代码
a as T
:将a
转换称为指定的类型T
,相似于Java
中的(T)a
。??=
:仅在变量为null
时才分配。void main() {
int a;
a ??= 1;
a ??= 2;
print(a);
}
复制代码
运行结果:
1
复制代码
expr1 ?? expr2
:若是expr1
不为null
,那么返回expr1
的值,不然返回expr2
的值。void main() {
String a;
String b = a ?? "default";
print(b);
}
复制代码
运行结果:
default
复制代码
?.
:仅当对象不为空时才执行后面的操做,省去了Java
中先判空,再去调用方法的步骤。class Person {
String name;
Person(this.name);
log() {
print(name);
}
}
void main() {
Person p;
String name = p?.name;
p?.log();
p = Person('a');
p.log();
}
复制代码
..
容许对同一对象执行一系列操做,能够省去建立临时变量的步骤。
class Person {
String name;
Person(this.name);
log() {
print(name);
}
}
void main() {
Person p = Person('a');
p..name = 'b'
..log();
}
复制代码
在Flutter
中,有不少将Function
也就是方法做为成员变量的使用,其做用相似于Java
当中的回调,当咱们的回调接口中只有一个抽象函数时,可使用这种方法代替。
typedef CalBuilder = int Function(int x, int y);
class Cal {
CalBuilder builder;
Cal(this.builder);
log() {
print('result=${builder(1, 2)}');
}
}
void main() {
Cal cal = Cal((a, b) => a + b);
cal.log();
}
复制代码
当函数执行时不须要强制传递参数时,可使用可选参数,可选参数时函数中的最后一个参数。
可选参数的语法为:
void function_name(param1, [param1, param2]) { }
复制代码
示例以下:
void main() {
func(1);
func(1,'2');
}
void func(int a, [String b, int c]) {
print(a);
print(b);
print(c);
}
复制代码
注意:若是当赋值给可选参数的实参数目不够时,那么必须按照形参类型定义的顺序依次赋值,不然没法编译经过。
与可选位置参数不一样,可选命名参数要求必须在传递值时指定参数名称。
void function_name(a, {param1, param2}) { }
复制代码
示例:
void main() {
func(1);
func(2, c:3);
}
void func(int a, {String b, int c}) {
print(a);
print(b);
print(c);
}
复制代码
不管是可选位置参数仍是可选命名参数,均可以定义默认值。语法为:
function_name(param1, {param2 = default_value}) { }
复制代码
示例:
void main() {
func(1);
func(1,'2');
}
void func(int a, [String b = 'default', int c]) {
print(a);
print(b);
print(c);
}
复制代码
输出结果:
1
default
null
1
2
null
复制代码
在Dart
中,经常使用的容器有List
和Map
,在使用上和Java
也有一些区别。能够参考下面的两篇文章,就不列举了: