Dart 基础(四)

前言
笔者在之前已经写了3篇Dart的基础文章了。
Dart 基础 (一)
Dart 基础 (二)
Dart 基础 (三)

笔者在本文中主要会分享:类、实例变量、构造方法、命名构造方法、实例方法、静态变量、静态方法、set、get 方法、extendsimplementsmixinabstractoverride相关的内容。

1.类

下边笔者先以Point 类为例,分享下关于实例变量构造方法命名构造方法实例方法静态方法静态变量set get方法 的内容。

Dart 是一种面向对象的编程语言,同时支持基于 mixin 的继承机制。mixin相关的内容会在下文解释。每个对象都是一个类的实例,所有的类都继承于 Object。 基于 Mixin 的继承 意味着每个类(Object 除外) 都只有一个超类,一个类的代码可以在其他 多个类继承中重复使用。

使用 new 关键字和构造方法来创建新的对象。 构造方法名字可以为 ClassName 或者 ClassName.identifier。
在Dart2.0的时候,创建新的对象的时候,new 关键字是可选的。当前Dart最新版本是2.4.0,2019-06-27 Dart开发团队发布2.4.0版本Dart。 Dart change log

1.1 实例变量

class Point {
  
  // 实例变量
  num x;
  num y;
}

1.2 构造方法:构造方法 定义一个和类名一样的方法

 // 构造方法 定义一个和类名一样的方法
  Point(num x, num y) {
    // this 关键字指当前的实例
    this.x = x;
    this.y = y;
  }
  
  // 由于把构造方法参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作
  // Point(this.x, this.y);

1.3 命名构造方法

 // 命名构造方法
  Point.fromJson(Map json) {
    // 只有当名字冲突的时候才使用 this。否则的话, Dart 代码风格样式推荐忽略 this。
    x = json['x'];
    y = json['y'];
  }

  Point.namedConstructor(Map json){
    x = json['x'];
    y = json['y'];
  }

命名构造方法使用场景有:模型类中解析数据场景。

举个简单例子:如返回一个列表数据的情况,返回数据可能是是一个包着多个字典的数组,那么,处理相应数据的时候,需要对数据进行相应的解析。解析的过程就可能用到命名构造方法。把一个个字典当做实例,提取出来。

[
    {
        "name":"QiShare1",
        "age":"1"
    },
    {
        "name":"QiShare2",
        "age":"1"
    },
    {
        "name":"QiShare3",
        "age":"1"
    },
    {
        "name":"QiShare4",
        "age":"1"
    },
    {
        "name":"QiShare5",
        "age":"1"
    },
    {
        "name":"QiShare6",
        "age":"1"
    },
    {
        "name":"QiShare7",
        "age":"1"
    },
]

1.4 实例方法

// 实例方法
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx*dx + dy*dy);
  }

1.5 静态方法

使用static关键字修饰的方法为静态方法,相当于类方法。使用类名可以直接调用。

// 静态方法
  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
void classDemo() {

    var jsonData = jsonDecode('{"x":2, "y":2}');
    // Create a Point using Point().
    var p1 = new Point(1, 1);
    print('p1点x坐标:${p1.x}');
    print('p1点y坐标:${p1.y}');

    // Create a Point using Point.fromJson().
    var p2 = new Point.fromJson(jsonData);
    print('p2点x坐标:${p2.x}');
    print('p2点y坐标:${p2.y}');

    num distance = p2.distanceTo(p1);
    print('p1到p2的距离: $distance');

    Map jsonData3 = {
      'x': 3,
      'y': 3,
    };

    Point p3 = Point.namedConstructor(jsonData3);
    print('p3点x坐标:${p3.x}');
    print('p3点y坐标:${p3.y}');
    
    num distance12 = Point.distanceBetween(p1, p2);
    print('p1和p2之间的距离 $distance12');
    
    }
    

输出内容

flutter: p1点x坐标:1
flutter: p1点y坐标:1
flutter: p2点x坐标:2
flutter: p2点y坐标:2
flutter: p1到p2的距离: 1.4142135623730951
flutter: p3点x坐标:3
flutter: p3点y坐标:3
flutter: p1和p2之间的距离 1.4142135623730951

1.6 静态变量

静态变量对于类级别的状态是非常有用的,笔者对这句话的理解是:静态变量可以由类名直接调用。

class Color {
  static const red =
      const Color('red'); // A constant static variable.
  final String name;      // An instance variable.
  const Color(this.name); // A constant constructor.
}

使用方式

    String colorName = Color.red.name;
    print('colorName:$colorName');

输出内容

colorName:red`

1.7 set get 方法

下边笔者举了一个类Rectangle的left、top、width、height的Set、Get方法的例子。

class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  num get right             => left + width;
      set right(num value)  => left = value - width;
  num get bottom            => top + height;
      set bottom(num value) => top = value - height;
}

使用方式

Rectangle rectangel = Rectangle(0, 0, 375, 667);
    print('rectangel.left:');
    print(rectangel.left);
    print('rectangel.right:');
    print(rectangel.right);
    print('rectangel.width:');
    print(rectangel.width);
    print('rectangel.height:');
    print(rectangel.height);
    print('rectangel.right:');
    print(rectangel.right);
    print('rectangel.bottom:');
    print(rectangel.bottom);

输出结果:

flutter: rectangel.left:
flutter: 0
flutter: rectangel.right:
flutter: 375
flutter: rectangel.width:
flutter: 375
flutter: rectangel.height:
flutter: 667
flutter: rectangel.right:
flutter: 375
flutter: rectangel.bottom:
flutter: 667

2. extends 与 implements

extends

关键字extends 用于继承父类的实例变量及方法等。Dart 只支持单继承。

implements

Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B’s API without inheriting B’s implementation, class A should implement the B interface.

每个类都隐式地声明了一个包含所有的实例变量和类已经实现的接口。
如果你想创建一个类A,没有继承类B,但是类A可访问类B的API,那么类A 应该实现类B的接口。
上边的内容,结合着下边的例子,笔者的理解是:Chicken隐式地声明了Animal 的实例变量,和类Animal 已经实现的方法。Chicken支持在没有继承类Animal的情况下,可访问类B的API。
一个类可以implements 多个类的API,所以implements算是一种变向实现多继承的方式。


class Animal {
  String name;
  void ability() {
    print('Animal 的能力');
  }
}

class Bird extends Animal {
  void ability(){
    print('bird can fly');
  }
}

class Fish extends Animal {
  void ability(){
    print('fish can swim');
  }
}

class Dog extends Animal {
  void ability(){
    print('dog can bark');
  }
}

class Chicken implements Animal {
  String name;
  void ability() {
    print('chicken can lay eggs');
  }
}

调用如上代码的方式及相应输出结果如下:

    Dog dog = Dog();
    dog.ability();
    Fish fish = Fish();
    fish.ability();
    Bird bird = Bird();
    bird.ability();
    Chicken chicken = Chicken();
    chicken.ability();
    
    

// 输出结果:
flutter: dog can bark
flutter: fish can swim
flutter: bird can fly
flutter: chicken can lay eggs

3. mixin

Mixins 是一种在多类继承中重用一个类代码的方法。笔者的理解是,mixin相当于是一个工具类,使用 with 关键字使用了mixin的类,就可以使用mixin中的代码。

Mixins are a way of reusing a class’s code in multiple class hierarchies.

To use a mixin, use the with keyword followed by one or more mixin names. The following example shows two classes that use mixins:

Mixin 是一种在多个类中重用某些代码的方式。
使用mixin ,需使用 with 关键字,with后边跟mixin的名,with 后边可以跟多个mixin名字,及可以同时使用多个mixin中的代码。下边笔者举了一个开发者学习基础语言的例子。

笔者定义了一个Developer的mixin,如果是iOS 开发者需要先学习C语言基础,如果是Android 开发者,需要先学习Java语言,如果是Flutter 开发者,需要先学习Dart 语言。

mixin Developer {
    bool isIOS = false;
    bool isAndroid = false;
    bool isFlutter = false;
    
    // 需要学习的基础语言
    void needLearnBaseProgram () {
      if (isIOS) {
        print('Need Learn C Firstly');
      } else if (isAndroid) {
        print('Need Learn Java Firstly');
      } else if (isFlutter) {
        print('Need Learn Dart Firstly');
      } else {
        print('May be need Learn Other Language');
      }
    }
    
  }

class FlutterDeveloper with Developer {
    String name;
    FlutterDeveloper(String name) {
        isFlutter = true;
        this.name = name;
    }
}
  

使用的相关代码:

    FlutterDeveloper flutterDeveloper = FlutterDeveloper('FlutterEnginerName');
    flutterDeveloper.needLearnBaseProgram();
    
    // 输出结果: flutter: Need Learn Dart Firstly

注意事项: 当在if else 场景下使用 bool 类型变量的时候,需要注意bool变量是否赋值过了,否则会有类似如下的异常信息。

flutter: The following assertion was thrown while handling a gesture:
flutter: Failed assertion: boolean expression must not be null

4. abstract

使用 abstract 修饰的类 记为抽象类。抽象类用于定义接口 及部分实现。

笔者举了如下例子:

创建了People 类,并且声明了 String skinColor();的抽象方法,创建并实现了 void ability() 方法;

abstract class People {
  String skinColor();
  void ability() {
    print('All can Communicate');
  }

}

class YellowPeople extends People {
  @override
  String skinColor() {
    String color = 'Yellow';
    print(color);
    return color;
  }
}

class BlackPeople extends People {
  @override
    skinColor() {
      String color = 'black';
      print(color);
      return color;
    }
}

class WhitePeople extends People {
@override
  skinColor() {
    String color = 'White';
    print(color);
    return color;
  }
}

下边是使用示例,及相应的输出结果。


YellowPeople yellowPeople = YellowPeople();
yellowPeople.ability();
yellowPeople.skinColor();

WhitePeople whitePeople = WhitePeople();
whitePeople.ability();
whitePeople.skinColor();

BlackPeople blackPeople = BlackPeople();
blackPeople.ability();
blackPeople.skinColor();
    
// 输出结果:
flutter: All can Communicate
flutter: Yellow
flutter: All can Communicate
flutter: White
flutter: All can Communicate
flutter: black

  • 抽象类不能创建实例。
  • 抽象方法为没有方法体的方法。只有抽象类中可以写抽象方法,其他普通类不可以。
    • 例:如果BlackPeople的skinColor 没有方法体即没有实现,则会报错如下:'skinColor' must have a method body because 'BlackPeople' isn't abstract.
      Try making 'BlackPeople' abstract, or adding a body to 'skinColor'.
  • 继承了抽象类的子类必须实现抽象方法
    • 以WhitePeople 为例,如果不实现skinColor 方法会报出如下错误:
      • Missing concrete implementation of People.skinColor.
      • Try implementing the missing method, or make the class abstract.

5. override

"5.1 override 运算符"及override toString

这里笔者对override 运算符添加了引号。至于原因,等大家看完了下边的内容之后,便会了解笔者的用意。下文提到的override和重写是一个意思。

先看下运算符重写的示例代码:

Vector 类,重写了+ 运算符和减运算符,以达到Vector可以直接进行加减的目的。笔者还重写了Vector类的toString 方法,便于查看Vector的x、y值。

class Vector {
  final int x;
  final int y;
  
  const Vector(this.x, this.y);

  Vector operator +(Vector v) {
    return Vector(x + v.x, y + v.y);
  }

  Vector operator -(Vector v) {
    return Vector(x - v.x, y - v.y);
  }
  
  @override
  String toString() {
    return 'runtimeType:' + this.runtimeType.toString() + ',x:' + x.toString() +',y:' + y.toString();
  }
  
}

使用Vector的+、-运算符,及重写toString后,使用Vector的示例代码及输出结果如下:

    Vector v1 = Vector(1, 1);
    Vector v2 = Vector(2, 2);
    Vector v3 = v1 + v2;
    Vector v0 = v2 - v1;
    print(v0);
    print(v3);

// 输出结果: 
flutter: runtimeType:Vector,x:1,y:1
flutter: runtimeType:Vector,x:3,y:3

重写toString的效果是:可控制print的对象的内容及格式。这一点便于非调试环境下查看一些具体错误信息。

上文笔者提到了重写运算符是加引号的原因如下:在笔者看来,运算符的重写有点跑题了。重写toString才算是重写。重写的toString的返回值、方法名和参数和父类Object都一样。如大家有不同理解,欢迎讨论。

参考学习网址

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

推荐阅读更多精彩内容