Dart语言基础(六)之面向对象扩展

简介

上一遍主要讲了面相对象的基础特性,这篇文章主要讲面向对象的扩展,分别以一下几个方面来讲

  • 继承,继承中的构造方法
  • 抽象类
  • 接口
  • Mixins,操作符的覆写

继承

  • 使用关键字extends继承一个类
  • 子类会继承父类可见的属性和方法,不会继承构造方法
  • 子类能够复写父类的方法、getter和setter
  • 单继承,多态性

在Person.dart文件中:

class Person {
  
  String name;
  int age;
  //私有属性
  String _favorite;
  //计算属性,判断是否成年
  bool get isAdult => age > 18; 
  void work() {
    print('person is working');
  }
  //私有方法
  void _run(){

    print('person is running');
  }
  //当继承person的子类要重写构造方法,不能继承
  Person(this.name,this.age);
}

在文件中import 'Person.dart'文件

import 'Person.dart';

void main() {

  var student = Student();
  student.study();
  student.name = '学生';
  student.age = 16; //可以访问可见属性
  // student._favorite = '打篮球'; //访问不了私有属性
  // student._run(); //访问不了私有方法
  //可以访问父类可见方法,可以重写父类的方法
  //子类work方法里面调用super的work方法
  /*
  打印结果:
  person is working
  student is working
  */
  student.work(); 

  //计算属性,通过age来计算是否成人
  //父类计算是大于18,子类重写大于15
  print(student.isAdult);  //YES

  //父类的引用,子类的实现
  Person person = new Student();
  // person.study();//提示找不到该方法
  if (person is Student) {
    //父类引动study方法,实际是子类去实现该方法
    person.study();
  }
}

class  Student extends Person {

  //stu自有的方法
  void study() {

    print('student is studying');
  }

  @override //表示复写父类的标识
  bool get isAudlt => age > 15;
  
  @override
  //学生可以重写父类的方法
  void work() {
    super.work();
    print('student is working');
  }
}

继承中的构造方法

  • 子类的构造方法默认会调用父类的无名无参构造方法
void main() {

  //默认会调用person的无名无参构造方法
  var student = new Student(); //Person的构造方法
}

class Person {
  
  String name;
  //无名无参的构造方法
  Person() {
    
    print('Person的构造方法');
  }
}

class Student extends Person {
  int age;
}

继承中的构造方法

  • 如果父类没有无名无参构造方法,则需要显示调用父类构造方法
  • 在构造方法参数后使用:显示调用父类构造方法

void main() {

  //Student('张三')相当于调用了Person.withName('张三')
  var student = new Student('张三');
  print(student.name); //张三
}

class Person {
  
  String name;
  //子类需要显示的父类构造方法,这两个其中之一
  Person(this.name);
  Person.withName(this.name);
}

class Student extends Person {
  
  int age;

  //Student(String name)就是显示调用super.withName(name)方法
  //下面两种方式都可以,但是都写的会报错,方法不能重载
  // Student(String name) : super(name);
  Student(String name) : super.withName(name);
}

构造方法执行顺序

  • 父类的构造方法在子类构造方法体开始执行的位置调用
  • 如果有初始化列表,初始化列表会在父类构造方法之前执行

void main() {

  //Student('张三')相当于调用了Person.withName('张三')
  var student = new Student('张三','男');
  print(student.name); 
  print(student.gender);
  /*
  打印结果:
    Person构造方法先执行
    Srudent构造方法后执行
    张三
    男
   */
}

class Person {
  
  String name;
  //子类需要显示的父类构造方法,这两个其中之一
  Person(this.name);
  Person.withName(this.name) {

    print('Person构造方法先执行');
  }
}

class Student extends Person {
  
  int age;
  final String gender ;


   //子类的初始化列表在父类构造方法之前,
  //父类构造方法执行在子类构造方法执行之前
  Student(String name, String gender):gender = gender ,super.withName(name) {

    print('Srudent构造方法后执行');
  }
  //初始化列表方法父类的构造方法之后编译会报错
  // Student(String name, String gender):super.withName(name),gender = gender;

}

抽象类

  • 抽象类使用abstract表示,不能直接被实例化
  • 抽象方法不能用abstract修饰,只声明方法,没有方法实现
  • 抽象类可以没有抽象方法
  • 有抽象方法的类一定得声明为抽象类

void main(List<String> args) {
  
  //抽象类不能被实例化
 var person = new Person(); //报错
  //抽象类只能通过子类继承来实现
  var student = new Student();
  student.run(); //run
}

abstract class Person {

  //抽象类中抽象方法不需要用abstract,不用实现。
  //子类继承去实现 
  void run();
}

//抽象类不能实例化,只能通过子类继承来实现实例化
class Teacher extends Person {

  @override
  void run() {

    print('teacher run');
  }
}

//抽象类不能实例化,只能通过子类继承来实现实例化
class Student extends Person {

  @override
  void run() {

    print('Student run');
  }
}

接口

  • 类和接口是统一的,类就是接口
  • 每个类都隐式的定义了一个包含所有实例成员的接口
  • 如果是复用已有类的实现,使用继承(extends)
  • 如果只是使用已有的外在行为,则使用接口(implements)
void main(List<String> args) {
  
  var student = new Student();
  student.run(); //student run
  print(student.age); //15

  var child = new Children();
  child.run(); //children run
}

 class Person {
   String name;
  int get age => 18;

  void run() {

    print('person run');
  }
    
}

//抽象类来作为接口
abstract class AbsPerson {

    void run();
}

//抽象类当成接口来调用,抽象类也是类的一种
//所以说类就是接口
//建议大家用抽象类来作为接口
class Children implements AbsPerson {
  @override
  void run() {
    // TODO: implement run
    print('children run');
  }
}

// 把Person作为接口来使用,类就是接口
//Person里面的所有属性方法都要重新实现
class Student implements Person {
  @override
  String name;

  @override
  // TODO: implement age
  int get age => 15;

  @override
  void run() {
    // TODO: implement run
    print('student run');
  } 
}

Mixins

  • Mixins类似于多继承,是在多类继承中重用一个类代码的方式
  • 作为Mixins类不能有显示声明构造方法
  • 使用关键字with连接一个或者多个Mixins类
void main(List<String> args) {
  
  //D多继承与A,B,C
  //D类的对象可以调用A,B,C的方法
  var d = new D();
  //A,B,C都有a()这个方法,会执行哪个类的a()方法
  //以为D extends A with B,C,按顺序执行
  //C在最后面,所以执行C的a()方法
  //b()方法同上原理
  d.a(); //C.a
  d.b();//C.b
  d.c();//C.c
}

class A {

  //D是继承A的,所以显示声明没有问题
  A() {

  }
  void a() {

    print('A.a');
  }
}

class B {

  //类B会报错,Mixins类不能显示创建构造方法
  // B() {

  // }
  void a() {

    print('B.a');
  }

  void b() {

    print('B.b');
  }
}

class C {

  //类B会报错,Mixins类不能显示创建构造方法
  // C() {

  // }
  void a() {

    print('C.a');
  }

  void b() {

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

    print('C.c');
  }
}

//用 D extends A with B,C形式实现实现多继承
//先继承一个类 再在with后面跟的就是Mixins类
//在B,C类要是显示的创建构造方法,D在继承Mixins类的B,C就是有错误
class D extends A with B,C {
  
}

  • 作为Mixins的类只能继承自Object

void main(List<String> args) {
  
  var a = new A();
  a.work(); //b.work
}

//B是Mixins类,只能继承与Object
//C并不是Object
// class B extends C {

//mixins只能继承Object
class B extends Object {
  void work() {

    print('B.work');
  }
}

class C {

}

//B是Mixins类
class A with B {

}

下面我讲一个实例,通过用抽象类和接口来实现一个类,这样能更好理解抽象类和接口的作用

void main() {

  var car = Car();
  car.work(); //Using Electric
  car.run(); //tyre run

  var bus = Bus();
  bus.work(); //Using oil
  bus.run(); //tyre run
}

//发动机
abstract class Engine {

  void work();
}

//燃油发动力
class OilEngine implements Engine {
  @override
  void work() {
   
    print('Using oil');
  }
}

//电力发动机
class ElectricEngine implements Engine {
  @override
  void work() {
    
    print('Using Electric');
  }
}

//轮胎
class Tyre {
  String name;
  void run() {
    print('tyre run');
  }
}

//声明类,这种是简写的方法,下面我写全
//一个汽车有轮胎并且是电发动机
class Car = Tyre with ElectricEngine;
// //下面是写全的方式
// class Car extends Tyre with ElectricEngine{

// }

class Bus = Tyre with OilEngine;

操作符覆写

  • 覆写操作符需要在类中定义
返回类型 operator 操作符 (参数1,参数2,...) {
    实现体
    rturn 返回值
}

  • 如果覆写 == ,还需要覆写对象的hashCode getter方法
  • 可覆写的操作符:
    <,+,|,[],>,/,^,[]=,<=,/,&,,>=,*,<<,==,-,%,>>

void main() {

  var p1 = new Person(18);
  var p2 = new Person(22);

  //> 操作符无法比较两个对象的大小
  //要覆写操作符 > 才能比较
  //覆写的返回值是bool
  p1 > p2;
  print(p1 > p2); //false

  print(p1.age); //18
  //通过覆写操作符
  //p1通过p1['age']取值
  print(p1['age']); //18
  print(p1['aa']); //0
}

class Person {
  
  int age;
  Person(this.age);
  //覆写操作符 > 
  bool operator > (Person p) {

    return this.age > p.age;
  }
  //覆写操作符 = 
  int operator [](String name) {

    if(name == 'age') {
      return this.age;
    }
    return 0;
  }
}

覆写操作符你可以自己多尝试,多实践实践,慢慢就会深有体会。

结尾

通过本篇文章,解了面向对象的拓展功能,

下一篇会主要讲一下Dart语言基础(七)之枚举和泛型,到时候大家关注一下。

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

推荐阅读更多精彩内容

  • java继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。 继承就是子类继...
    863cda997e42阅读 666评论 0 1
  • 面向对象笔记 一、 对象在内存中的存放方法以及被调用过程 class文件首先被加载到方法区中的class文件内容区...
    VictorBXv阅读 464评论 0 2
  • 1 面向对象No6 面向对象 OO Object Oriented 编程时以对象为单元,封装数据和逻辑,以此提...
    征程_Journey阅读 1,141评论 0 2
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 1,201评论 0 5
  • 之前就知道简书,也看过简书周刊,可是没有更多的关注,希望以后能每天让自己写些东西,希望能坚持下去!
    唐小风阅读 105评论 0 1