第7章 Dart面向对象 -- 类和函数

Dart是一种面向对象的语言,具有类和基于mixin(混入)的继承。每个对象都是一个类的实例, 与Java语言的继承体系类似,Dart中的每个类(除了Object)都只能有一个超类,但是类体可以在多个类层次结构中重用。

1. 类

1.1 普通类

1.1.1 普通成员

Dart使用class关键字表示一个类,对象具有由函数数据(可以理解为Java语言的方法属性)组成的成员。
与Java语言类似的是使用new XXX()方式创建类的对象,然后使用“.”或“?.”访问对象的函数或数据。
示例代码:

main() {
  var p1 = new Person();
  var p2 = new Person();
  p1.num = 10;
  p1.name = "赵四";
  p2.num = 20;
  p2.name = "刘能";
  p1.display();
  p2.display();
}
class Person{
  int num;
  String name;

  void display(){
    print("编号:${num}, 名字:${name}");
  }
}

运行结果:

运行结果

如果Person类定义在其他dart文件中,需要在main方法前引入其他dart文件。

import 'person.dart';
1.1.2 静态static

与Java中的静态static关键字类似,Dart语言中的static表达了“类成员”的含义,即这个成员不属于某个对象,而是属于整个类。
示例代码:将1.1.1示例中的num数据更改为“类数据”

main() {
  var p1 = new Person();
  var p2 = new Person();
  Person.num = 10;
  p1.name = "赵四";
  Person.num = 20;
  p2.name = "刘能";
  p1.display();
  p2.display();
}
class Person{
  static int num;
  String name;

  void display(){
    print("编号:${num}, 名字:${name}");
  }
}

运行结果:

运行结果

可以看到Person类的num属性通过类进行控制,不能通过对象控制。,Dart语言中对于“静态”方式调用的约束和理解与Java相似。

  • 静态函数只能访问类中其他的静态成员,不能访问普通的成员。(静态函数只能访问静态函数和静态数据)
  • 非静态函数可以访问类中的任意其他成员(非静态函数可以访问静态函数和静态数据)
  • 类的外部只能通过类名.xxx的方式访问静态资源,不能使用对象.xxx的方式访问静态资源。(Java语言允许对象访问静态资源,Dart语言不允许这样做)

1.2 可调用类(Callable Class)

Dart语言中允许以使用函数的方式来调用类,必须通过在类中实现call()方法完成将类模拟成函数的操作
示例代码

main(){
  var c = new Cxtest();
  var x = c(2,3);
  print(x);
}
class Cxtest{
  call(dynamic a, dynamic b){
     return a+b;
  }
}

运行结果:5

1.3 枚举(enum)

与Java中枚举的使用方式类似
声明枚举

enum Color{red, green, blue, yellow, white, black}

使用枚举

 var c = Color.blue;

遍历枚举

List<Color> list = Color.values;
list.forEach((Color c) => print("颜色:${c}"));

1.4 泛型编程(类型参数化)

Dart中的泛型使用方式与Java语言类似,使用泛型带来编程中的许多好处,此处不再累述(详见本人Java文章:《第16章 集合类》第4小节-泛型)。

在Dart中也可以向Java一样使用泛型编程,这种形式可以理解为将输入的类型参数化。
泛型声明可以使用在

  • 函数参数
  • 函数返回值

演示示例

main(){
  DataUtil<int> d = new DataUtil();
  d.show(32);
}
class DataUtil<T>{
  void show(T a) => print("数据:${a}");
}

此处也可以像Java语言一样使用T extends num形式约束泛型只能输入num或num类型的子类。详细用法请参照《第8章 Dart面向对象 -- 类的继承与混入(mixin)》)的第6节。

2. 函数

2.1 普通函数

Dart是一种纯粹的面向对象的语言,所以即使是函数也是对象。类似Javascript语言,Dart中的函数属于Function类型。可以通过函数指定变量或者把函数作为其他函数的参数。main函数是程序入口
Dart语言中函数结构与Java语言中的方法类似

返回值类型 函数名(参数列表){
  函数体代码
  return 返回值;
}

演示示例:两个数字相加的方法,并返回相加结果

main() {
  var c = addition(3, 2.14);
  print(c);
}

num addition(num a, num b){
  return a+b;
}

可以使用=>表示函数内容
比如

void main(){
  runApp(new MyApp());
}

等价于

void main() => runApp(new MyApp());

如果某个函数的返回值类型是void,可以省略void关键字
比如

void main(){}

等价于

main(){}

2.2 构造函数

构造函数是在创建Dart类实例(对象)时进行调用的,可以参考Java的构造方法进行理解。

2.2.1 常规构造函数

与Java语言的语法类似,在Dart语言中如果没有显式声明构造函数,系统会提供默认无参的构造函数,但如果显式声明了构造函数,系统不再提供默认的无参构造函数。
构造函数不能声明返回值类型,函数名必须与类名一致

类名(参数列表){
}

演示示例

void main(){
  var a = new NumberTest(2, 3);
  a.display();
}
class NumberTest{
  num a;
  num b;
  NumberTest(num a, num b){
    this.a = a;
    this.b = b;
  }
  void display(){
    print("数据:${a},${b}");
  }
}

上面示例的构造函数也可以写成下面这种形式,效果是一样的。

 NumberTest(this.a, this.b){}
2.2.2 命名构造函数

Dart的语法不支持函数重载,无法像Java语言一样使用构造方法重载。因此当需要使用多个构造函数时,需要使用命名构造函数这种形式。
演示示例

void main(){
  var a = new NumberTest(2,3);
  var b = new NumberTest.cons1();
  var c = new NumberTest.cons2(5);
  a.display();
  b.display();
  c.display();
}

class NumberTest{
  num a;
  num b;

  NumberTest(this.a, this.b){} //构造函数
  NumberTest.cons1(){//命名构造函数1
    this.a = 0;
    this.b = 0;
  }
  NumberTest.cons2(this.a){//命名构造函数2
    this.a = a;
    this.b = 0;
  }
  void display(){
    print("数据:${this.a},${this.b}");
  }
}

运行结果


运行结果
2.2.3 构造函数之间的调用

当需要构造函数之间互相调用时需要使用this关键字
演示示例

void main(){
  var a = new NumberTest(2,3);
  var b = new NumberTest.cons1();
  var c = new NumberTest.cons2(5);
  a.display();
  b.display();
  c.display();
}

class NumberTest{
  num a;
  num b;

  NumberTest(this.a, this.b){} //构造函数
  NumberTest.cons1() : this(0,0); //命名构造函数1
  NumberTest.cons2(num a) : this(a, 0); //命名构造函数2
  void display(){
    print("数据:${this.a},${this.b}");
  }
}
2.2.4 工厂构造函数

通过使用factory声明工厂构造函数,控制对象实例的数量。
语法

factory 类名(参数列表){
}

工厂函数中不能使用this关键字,有时需要借助命名构造函数完成功能
演示示例

void main(){
  var a = FactoryTest("haha");
  var b = FactoryTest("haha");
  var c = FactoryTest("xixi");
  print(a.hashCode);
  print(b.hashCode);
  print(c.hashCode);
  print(a == b);
}

class FactoryTest{
  String _name;
  static Map<String, FactoryTest> cache_map = new Map();

  factory FactoryTest(String name){ //工厂构造函数
    if(cache_map.containsKey(name)){
      return cache_map[name];
    }else{
      FactoryTest temp = FactoryTest.createInstance(name);
      cache_map[name] = temp;
      return temp;
    }
  }
  FactoryTest.createInstance(this._name);//命名构造函数
  void test(){
    print(_name);
  }
}

运行结果

运行结果

2.3 可选参数函数

Dart语言支持像Javascript中函数传递json的方式一样使用可选参数函数
声明语法

返回值类型 函数名({参数1,参数2...参数n})

演示示例

void main(){
  display1(1, "haha", 3.14); //必须补足实参
  display2(a:1, c:3.14);  //选择实参传入,此时只提供了a和c的实参
}

void display1(dynamic a, dynamic b, dynamic c){
  print("a:${a},b:${b},c:${c}");
}
void display2({dynamic a, dynamic b, dynamic c}){
  print("a:${a},b:${b},c:${c}");
}

运行结果

运行结果

可以为可选参数函数设置参数的默认值

void display2({dynamic a, dynamic b = 0, dynamic c}){
  print("a:${a},b:${b},c:${c}");
}

上面的代码将参数b的默认值设置为0,再次调用display2函数会得到如下结果:


运行结果

2.4 函数参数和匿名函数

Dart语言中函数被认为是一种类型Function,所以也可以将函数作为另一个函数的参数使用,此时类似Javascript语言中的函数参数的使用方式。

2.4.1 函数参数

演示示例:使用函数haha作为回调函数的参数

void main(){
  doSomeThing(3, haha);
}
void doSomeThing(num a, Function callback){
  print("do sth.${a} times");
  callback();
}
void haha(){
  print("done, good job");
}

运行结果

运行结果

2.4.2 匿名函数

如果不想显示声明haha函数,可以通过声明匿名函数的方式来完成函数参数的实现
语法

(){
  //功能代码
}

演示示例:使用匿名函数

void main(){
  doSomeThing(3, (){
    print("done, good job");
  });
}
void doSomeThing(num a, Function callback){
  print("do sth.${a} times");
  callback();
}

如果只有一行代码也可以写成

doSomeThing(3, () => print("done, good job"));

2.5 闭包

一个函数的作用范围为其函数体的{}内。当函数定义和函数表达式位于另一个函数的函数体内,内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
演示示例

void main(){
  var r = 2;
  var getCircleArea = (){
      const PI = 3.1415926536;
      return PI*r*r;  //匿名方法可以访问外部函数的数据r,形成闭包。
  };
  print(getCircleArea());
}

2.6 等价函数

由于函数可以被当做变量看待,那么当多个变量指向同一个函数时,它们之间就可以理解为互为等价函数
演示示例

void topMethod(){}

class Test{
  static void staticMethod(){}
  void instanceMethod(){}
}
void main(){
  dynamic temp1 = topMethod;
  dynamic temp2 = Test.staticMethod;
  dynamic t1 = new Test();
  dynamic t2 = new Test();
  dynamic temp3 = t1.instanceMethod;

  print("顶级函数比较结果: ${temp1 == topMethod}");
  print("静态函数比较结果: ${temp2 == Test.staticMethod}");
  print("实例函数比较结果1: ${temp3 == t1.instanceMethod}");
  print("实例函数比较结果2: ${temp3 == t2.instanceMethod}");
}

运行结果

运行结果

2.7 初始化列表

可以在构造函数体运行之前初始化实例变量,用逗号分隔初始化。
演示示例

main (){
  new NumberTest(2, 3).display();
}

class NumberTest{
  num x;
  num y;
  num z;
  NumberTest(this.x, this.y)
    : z=x+y{}  //带有初始化列表的构造方法,方法体内没有写代码
    
  void display(){
    print(z);
  }  
}

运行结果:5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容

  • 2018.11.14日,在家附近的琴行报名了古典吉他班,一对二教学。 我是跟一个初二的小男孩一起上课,他是民谣吉他...
    雨听夜说阅读 1,103评论 0 6
  • 我站在桥上不是为了看风景, 我想登上生命之上看见生命。 为了看见生命的丑陋与卑微, 我又不得不低头看见自己。 我说...
    宁民阅读 250评论 0 6
  • 1、vi 字符串查找(常用):/要查找的字符串 敲enter开始查找 n代表下一个 N代表上一个从上往下找...
    跟我念一遍阅读 207评论 0 1