Dart - extends, Mixin, implements

1,424 阅读4分钟

重点:

  • implements必须实现接口类中的所有属性和方法(普通方法和抽象方法)。

这篇博客写的很好: www.jianshu.com/p/18e8d285c…

  1. Java和Dart的对比:

    在使用Java语言设计类之间关系的时候,我们会接触到 组成单元 和 关系连接 这两类概念:

组成单元:普通类、abstract抽象类,interface接口。
关系连接:implements实现,extends继承。

而在Dart当中,对于这两类概念进行了增减:
组成单元:普通类,abstract抽象类、mixin。
关系连接:implements实现、extends继承、with混入。

最大的不同有两点:

去掉了interface。 增加了混入的概念。

一、组成单元

  1. 普通类
    Java和Dart没有区别

  2. 抽象类
    Java和Dart的抽象类定义时大体是一样的,我们可以在其中定义变量、普通方法、抽象方法,它和普通类最大的区别就是 抽象类不能实例化。

Java和Dart在使用抽象类时有一点不同:Dart在定义抽象方法时,不需要用abstract修饰。

abstract class DartAbs {
  void absMethod();  //没有实现体的方法-抽象方法,Dart中不需要abstract修饰
} 
  1. interface接口
    Dart中没有interface关键字定义接口类,普通类和抽象类都可以作为接口类。
    顺带我们复习一下Java中abstract和interface的一些要点:
  • 抽象类和接口都不能被实例化。
  • 抽象类要被子类继承,接口要被类实现。
  • 接口只能做方法的声明,抽象类可以做方法的声明,也可以做方法的实现。
  • 接口里定义的变量只能是公共的静态常量,抽象类中的变量可以是普通变量。
  • 抽象类里的抽象方法必须全部被子类实现;接口的接口方法必须全部被子类实现,否则只能为抽象类。
  • 抽象类里可以没有抽象方法。
  • 如果一个类里有抽象方法,那么这个类只能是抽象类。
  • 抽象方法要被实现,所以不能是静态的,也不能是私有的。
  • 接口可继承接口,并可多继承接口,但类只能单继承。

二、连接关系

  1. extends继承
    Dart和Java一样,都是单继承。

    子类可以继承父类里面 可见的属性和方法。
    对于Java来说,可见指的是非private修饰,
    对Dart来说,指的是非下划线_开头。

    子类调用父类的方法,使用super关键字。
    子类不会 继承 父类的构造函数。

继承父类的方法,不一定需要重写

  1. implements实现
    implements实现多个类或抽象类,实现了“多继承”
    A implements B,A中都需要实现B中所有的属性和方法(不管是普通方法还是抽象方法),继承不一定需要重写!如果要创建一个 A 类,A 要支持 B 类的 API ,但是不需要继承 B 的实现, 那么可以通过 A 实现implements B 的接口。
class Implements {
  String a;
  void base() {
    print('base');
  }
    
  void log() {
    print('extends');
  }
  
}

class Log implements Implements {
  String a = "hello"; //没有这句,则会报错,因为必须实现接口类中所有的属性和方法
  
  base() {
    print('log#base');
  }
  
  log() {
    print('log' + a);
  }
  
}

void main() {
  Log().log();
}

三、mixin,with混入
通过创建一个继承自 Object 且没有构造函数的类,来 实现 一个 Mixin 。 如果 Mixin 不希望作为常规类被使用,使用关键字 mixin 替换 class。
也就是说,with混入的类必须没有构造函数,可以是class定义的类,但是最好用mixin关键字来定义这样的类。

mixin MusicalPerformer on Musician {
  // ···
}

mixin on
混入MusicalPerformer的类必须继承Musician
下面有个例子:

abstract class Super {
  void method() {
    print("Super");
  }
}

class MySuper implements Super {
  void method() {
    print("MySuper");
  }
}

mixin Mixin on Super {
  void method() {
    super.method();//15行
    print("Sub");
  }
}

class Client extends MySuper with Mixin {

}

输出
MySuper
Sub

第15行调用super.method()会先查找MyMixin中有没有对应的方法,发现有该方法,然后因为MyMixin限定子类必须继承或实现Super,所以第15行方法中的super.method()会调用MyMixin的子类所extend的父类的method方法,在这里就是MySuper的method()方法,所以输出MySuper,然后输出Sub。

四、冲突
如果同时存在extends, with,并且它们都定义了相同的方法名.
with修饰的会覆盖extends中修饰的同名方法。
with列表中后一个的会覆盖之前的。

再加上implements

class Extends {
  
  void log() {
    print('extends');
  }
  
}

mixin Mixins {
  
  void log() {
    print('mixin');
  }
  
}

mixin Mixins2 {
  
  void log() {
    print('mixin2');
  }
  
}

class Implements {
  
  void log() {
    print('implements');
  }
  
}

class Log extends Extends with Mixins, Mixins2 implements Implements {}

void main() {
  Log().log();
}

输出结果为:mixin2

这里我们发现了一个奇怪的现象:虽然我们加上了implements,但是Dart居然没让我们实现Implements.log()方法!

这是因为在这种情况下,它识别到我们从with和extends中获得了log()方法的能力,因此调用的是Mixins2.log()。

假如我们对Implements#log方法进行实现:

class Log extends Extends with Mixins, Mixins2 implements Implements {
  
  void log() {
    print("implements log");
  }
}

输出的结果为:implements log