面向Kotlin与Java开发者的Dart快速入门(八)继承与Mixins

Dart入门教程 同时被 2 个专栏收录
15 篇文章 0 订阅
31 篇文章 1 订阅

在这里插入图片描述

隐式接口


Java中我们总是把接口和抽象类放到一起理解:接口是极致抽象的抽象类。
Dart中接口和类是统一的,每个类同时也是一个接口:

  • 没有interface关键字,声明class的同时隐式地创建同名接口
  • 类中的非私有的成员可以通过接口对外暴露,但需要被实现
  • 与Java一样,使用implements 关键字实现接口
  • 抽象类同样具有隐式接口
// Person声明的同时,创建同名接口,内有方法greet()
class Person {
  // 接口不含有private变量
  final _name;

  // 接口不包含构造函数
  Person(this._name);

  // 接口中没有方法实现
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// 实现Person接口
class Impostor implements Person {
  get _name => '';

  // 必须要实现greet方法
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

因为类同时也是接口,extendsimplements关键字都是合法的,但意义完全不同,需要注意


继承


与Java的继承没有区别:

  • 使用extends关键字
  • 只允许单继承

方法重写

注意是重写不是重载,Dart没有方法重载

  • 与Java一样,可通过@Override注解表示一个重写方法,当然可以省略
  • 方法重写时可以通过covariant关键字缩小参数类型,这是Java或Kotlin中没有的
class Animal {
  void chase(Animal x) { ... }
}

class Mouse extends Animal { ... }

class Cat extends Animal {
  void chase(covariant Mouse x) { ... }
}

运算符重载

虽然正确的英文是Overridable operators,但是类似功能总是被译成运算符重载,whatever。
虽然Java中没有,Kotlin、C++等都有此功能。

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}

Java中我们要求重写equals的同时必须重写hashcode,Dart中也是一样的, 所以我们对==进行运算符重载时,不要忘了hashcode

class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // Override hashCode using strategy from Effective Java,
  // Chapter 11.
  @override
  int get hashCode {
    int result = 17;
    result = 37 * result + firstName.hashCode;
    result = 37 * result + lastName.hashCode;
    return result;
  }

  // You should generally implement operator == if you
  // override hashCode.
  @override
  bool operator ==(dynamic other) {
    if (other is! Person) return false;
    Person person = other;
    return (person.firstName == firstName &&
        person.lastName == lastName);
  }
}

void main() {
  var p1 = Person('Bob', 'Smith');
  var p2 = Person('Bob', 'Smith');
  var p3 = 'not a person';
  assert(p1.hashCode == p2.hashCode);
  assert(p1 == p2);
  assert(p1 != p3);
}

noSuchMethod()

Java或Kotlin中没有类似功能,类似于Ruby的method_missing
因为Dart中存在dynamic类型,无法保证类型安全的情况下有可能被调用一个不存在的方法。通过重写noSuchMethod()方法,可以拦截这种非法调用。

只有当被调用对象满足以下三个条件其中之一时,noSuchMethod()才有可能被调用:

  • 被调用者是一个dynamic类型(此时若不重写noSuchMethod,会调用Object#noSuchMethod
  • 被调用者是一个抽象类类型(此时若不重写noSuchMethod,会调用Object#noSuchMethod
  • 被调用者是一个普通类类型,此时如果重写了noSuchMethod,则允许存在不被实现的方法(有可能被错误调用)
class A {
  @override
  void noSuchMethod(Invocation invocation) => print("method ${invocation.memberName} is missing");
}

class B {
  // 因为重写了noSuchMethod,所以hoge()可以没有实现
  void hoge();

  @override
  void noSuchMethod(Invocation invocation) => print("method ${invocation.memberName} is missing");
}


void main() {
  dynamic a = A();
  a.hoge();

  // hoge()没有实现也照样能实例化
  B b = B();
  b.hoge();
}

Mixins


mixin是实现多继承的重要方式,Java和Kotlin中没有类似功能,Javascript和Python中有相似概念。

  • 使用with关键字,可以同时“继承”多个mixin类
  • mixin类mixin关键字替代class关键字,无构造方法,也不需要调用supermixin关键字是2.1之后引入的,2.1之前使用 abstract class,再阅读一些老项目代码时需要注意
mixin AndroidEngineer {
  void implementAndroidApp() {
    print("got it!");
  }
}

mixin IOSEngineer {
  void implementIOSApp() {
    print("Jobs!!");
  }
}

class Person {
}

class FlutterEngineer extends Person with AndroidEngineer, IOSEngineer {
}

void main() {
  final e = FlutterEngineer();
  e.implementAndroidApp();
  e.implementIOSApp();
}

extends不可缺

with的使用至少要伴随一个extends,干爹可以有多个,但必须有且仅有一个亲爹。如果只想继承mixin类时,最不济可以这样写 :extends Object with 〜〜

菱形继承问题?

OOP之所以不允许多继承,主要是为了避免菱形继承问题
在这里插入图片描述
Derivefun1究竟来自Base1还是Base2

  • 继承关系会按照如下优先级选取fun1with > extend > implements
  • 当with后有多个mixin类时,会按照从右往左的顺序选取fun1

mixin类的继承

mixin类要么直接继承Object,要么通过on关键字继承其子类extends的目标类。

因为mixin类需要使用on目标类的方法,所以要使用mixim类就必须继承on目标类,以提供mixin所需的方法

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

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

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

class Client extends MySuper with MyMixin {}

void main() {
  Client().method();//23行
}

上面代码输出结果:

MySuper
Sub
  • 23行会先查找MyMixin中有没有对应的方法
  • 15行因为MyMixin限定子类必须继承或实现Super,所以会调用MyMixin子类所extend的父类的method
  • 虽然MyMixin继承的是Supert,但是子类的直接父类是MySuper,所以输出是MySuper后跟Sub


返回首页:Dart入门教程

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值