Dart系列-面向对象(二)

周末学习了一下Dart语言,按照慕课网Flutter开发第一步-Dart编程语言入门教程进行学习,所以记录一下,感觉慕课网的老师辛苦做的视频教程,说得很清楚,有基础学起来很轻松也很快,本篇来学习dart的面向对象(二)。

继承

dart作为面向对象的语言,所以也有面向对象的三大特性,封装、继承、多态。封装就是之前的_前缀,而dart以库作为单位的,而库则是dart中的文件。接下来我们先看继承。

  • 继承。使用extends关键字。格式和Java的是一样的。继承是复用的一种手段,子类继承父类,会继承父类的所有公开属性和公开方法(包括计算属性),私有的属性和方法则不会被继承。子类可以覆写父类的公开方法。
class Person {
  String name;
  int age;

  //私有属性,不能被访问
  String _birthday;

  //是否成年,计算属性
  bool get isAdult => age > 18;

  void run() {
    print('run -> name=$name, age=$age');
  }
}

class Student extends Person {
  void study() {
    print('study...');
  }

  //复写计算属性,加上@override注解
  @override
  bool get isAdult => age > 15;

  //复写方法
  @override
  void run() {
    print('student run...');
  }
}

void main() {
  var student = new Student();
  student.study();
  //继承Person的可见属性
  student.name = 'wally';
  student.age = 17;
  print('是否成年:${student.isAdult}');
  student.run();
}
  • 多态。子类通过覆写覆写中的方法,在构造时,使用父类类型接收,调用父类方法则调用到了子类覆写的方法,则出现了多态。多态后,只能调用父类中公开的方法和属性,不能访问到子类的公开属性和方法了,如果要访问,则需要强转后调用。
//多态
Person person = new Student();
person.name = 'barry';
person.age = 19;
//多态后,只能访问父类中的属性和方法
person.run();
//不能访问子类的方法
//person.study();

//如果需要访问子类的方法,就需要强转
if (person is Student) {
    person.study();
}

继承中的构造方法

通过继承我们复用了父类的属性和方法,而构造方法,也会被复用,但和Java的有些许不同。

  • 子类默认继承父类中的无参构造方法。
class Person {
  String name;
  
  //重写无参构造方法
  Person() {
    print("person...");
  }
}

class Student extends Person {
}
  • 如果父类没有无参构造方法,只有有参构造或命名构造放方法,则子类需要显示调用父类的有参构造方法或者命名构造方法,还可以结合初始化列表进行使用。
class Person {
  String name;
  
  //如果父类没有无参构造方法,只有有参构造或命名构造放方法,则子类需要显示调用父类的有参构造方法或者命名构造方法
  Person(this.name);

  Person.withName(this.name);
}

class Student extends Person {
    final String gender;
    //有参构造方法,调用父类的有参构造方法
    Student(String name, String gender)
      : gender = gender,
        super(name);
        
    //子类中的命名构造方法也是一样
    Student.withName(this.name, this.gender)
        super.withName(name);

    //如果gender在初始化列表中初始化也是可以的
Student.withName(String name) : super.withName(name);
  Student.withName(String name, String g)
      //初始化列表
      : gender = g,
        super.withName(name);
}

抽象类

  1. 抽象类,和Java一样,使用abstract关键字声明为抽象类。
  2. 抽象类中声明抽象方法,子类必须实现,而Java的抽象方法必须使用abstract关键字修饰,而dart则不需要,只要方法只有方法声明,没有实现即为抽象方法。
  3. 抽象类可以有抽象方法和实例方法,甚至可以没有抽象方法,这个和Java是一致的。
  4. 抽象类不能被实例化,只有子类可以。
//abstract修饰类,该类则为抽象类
//抽象类可以没有抽象方法
//没有实现的方法的类,必须是抽象类
abstract class Person {
  //没有实现的方法就是抽象方法,不需要加abstract
  void run();
}

class Student extends Person {
  //复写父类的抽象方法
  @override
  void run() {
    print('run...');
  }
}

void main() {
  //Person抽象类,不能实例化
  //Person person = new Person();
  Person person = new Student();
  person.run();
}

接口

和Java一样,dart也有接口,但是和Java还是有区别的。

  1. 首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。
  2. 同样使用implements关键字进行实现。
  3. 但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
class Person {
  String name;

  //计算属性
  int get age => 18;

  void run() {
    print('Person run...');
  }
}

//dart的接口,类也可以作为接口,使用implements关键字进行实现,需要将所有属性和方法都实现...
class Student implements Person {
  @override
  String name;

  @override
  int get age => null;

  @override
  void run() {

  }
}
  • 一般会使用抽象类进行实现。
//dart的接口有点奇怪,所以一般会将抽象类作为接口来使用
abstract class Person {
  void run();
}

class Student implements Person {
  @override
  void run() {
    print('student...run...');
  }
}

var student = new Student();
student.run();

Mixins

Mixins,中文翻译过来为混入。dart和Java等高级语言一样,没有多继承,只有单继承,而dart解决多继承的问题,实现的是Mixins,而Java为接口多实现。

  • 要使用Mixins,必须让类继承一个类(Object不算),再使用with关键字将多个类标识为被混入的类。
void main() {
  D d = new D();
  d.a();
  d.b();
  d.c();
}

class A {
  void a() {
    print('A.a()...');
  }
}

class B {
  void b() {
    print('B.b()...');
  }
}

class Test {}

//作为mixins的类,只能继承Object
//class C extends Test {
class C {
  //作为mixins的类,不能有构造方法
//  C() {
//
//  }

  void c() {
    print('C.c()...');
  }
}

//mixins,需要先继承一个类,再机上with关键字去混入其他类
//如果混入的类中的方法,多个类中都存在,那么该类继承的的方法为最后一个混入的类
class D extends A with B, C {}
  1. 然而,被混入的类,不能有构造方法。
  2. 被混入的类,不能继承其他类,只能继承Object。
  3. 如果多个混入的类中都有同一个方法声明,则宿主类会取最后一个混入的类的方法,所以是按with关键字后写的最后一个类中的方法,是按顺序来的。

汽车例子,使用混入,实现组合功能

  • 一辆汽车,有多则部件组成,例如引擎和轮胎,而引擎有电动引擎或油驱动引擎。
//引擎抽象类
abstract class Engine {
  //有一个运行的抽象方法
  void work();
}

//油引擎
class OilEngine implements Engine {
  @override
  void work() {
    print('work with Old');
  }
}

//电动引擎
class ElectricEngine implements Engine {
  @override
  void work() {
    print('work with Electric');
  }
}

//轮胎
class Tyre {
  String name;

  //一个跑的方法
  void run() {
  }
}
  • 声明混入,前面说到mixins需要强制继承一个类后才能通过with关键字进行混入其他类。其实还有将extends关键字换为=号的简写方法。
//mixins简写
//class Car = Tyre with ElectricEngine {}

//完整写法
class Car extends Tyre with ElectricEngine {
    //新能源电动车
}

//其实就是组合的方式
class Bus extends Tyre with OilEngine {
    //传统油驱动大巴士
}

操作符覆写

  • 在比较2个类时,在Java中,我们会使用equas()方法,而dart比较内容是使用==号,Java中==号是比较对象的内存地址。当我们需要比较2个Person对象的年龄时,Java中需要取出age属性再通过比较运算符进行比较。而dart则提供了更强大的,操作符覆写特性。通过operator关键字,覆写指定的操作符。

  • 例如比较2个Person类对象的age年龄,使用>号操作符,通过operator覆写,则不需要将age属性取出再进行比较运算符比较。

class Person {
  int age;

  Person(this.age);

  //复写>操作符,使用operator关键字
  bool operator >(Person person) {
    return this.age > person.age;
  }
}

//Person person1 = new Person(18);
Person person1 = new Person(20);
Person person2 = new Person(20);
print(person1 > person2);
  • 再例如我们在map中使用的[]取值符号,在对象中也可以进行复写,从而能将类属性用字符串的方式取出再返回。
class Person {
  int age;

  Person(this.age);

  //复写>操作符,使用operator关键字
  bool operator >(Person person) {
    return this.age > person.age;
  }

  //重写取值[]操作符
  int operator [](String str) {
    if (str == 'age') {
      return age;
    }
    return 0;
  }
}

Person person1 = new Person(18);
//取出age字段的值
print(person1['age']);
//没有name字段,返回0
print(person1['name']);
  • 还可以复写==比较是否相等运算符,==在dart中为比较内容,而我们的自定义类中比较内容是需要我们去自定义的,所以就可以覆写==运算符。并且同时复写hashCode()方法。
class Person {
  int age;

  Person(this.age);

  //复写==比较操作符
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Person && runtimeType == other.runtimeType && age == other.age;

  @override
  int get hashCode => age.hashCode;
}

Person person1 = new Person(20);
Person person2 = new Person(20);
//年龄相同时,为相等
print(person1 == person2);

总结

本篇我们学习了面向对象(二),学习到了继承、构造方法继承、抽象类、接口、Mixins混入以及操作符复写,下一篇,我们将进行学习枚举和泛型。

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