类继承与成员重写

继承类 Extend a class

使用 extends 关键字,由父类(superclass / 超类)派生出子类(subclass)

使用 super 关键字,在子类中调用父类的成员(方法、构造器等)

class Television {
  void turnOn() {
     ...
     //父类方法中的执行代码
  }
}

// SmartTelevision 是子类,Television 是父类
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // 调用父类 turnOn 方法
    //子类中特有的代码
    ...
  }
}Code language: Dart (dart)

例如电视机是父类,智能电视是子类,智能电视继承了电视。

extends 还有另一种使用场景:泛型章节中参数化类型相关内容。

具体例子
class Television {
  void turnOn() {
    print("电视通电,启动基础画面输出");
  }
}

// SmartTelevision 是子类,Television 是父类
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // 调用父类 turnOn 方法
    //子类中特有的代码
    print("智能电视:启动网络模块、加载智能系统主页");
  }
}

void main() {
  // 普通电视实例
  Television normalTv = Television();
  print("===== 普通电视开机 =====");
  normalTv.turnOn();

  // 智能电视实例
  SmartTelevision smartTv = SmartTelevision();
  print("\n===== 智能电视开机 =====");
  smartTv.turnOn();
}Code language: Dart (dart)

运行结果

D:\dartdemo\firstdart>dart run
Building package executable... (1.4s)
Built firstdart:firstdart.
===== 普通电视开机 =====
电视通电,启动基础画面输出

===== 智能电视开机 =====
电视通电,启动基础画面输出

重写成员 Overriding members

1. 可重写内容

子类可以重写:实例方法(包括运算符)、getter、setter

2. @override 注解

作用:显式声明当前方法是主动重写父类成员,编译器辅助校验。

class Television {
  set contrast(int value) {}
}

class SmartTelevision extends Television {
  @override //告诉编译器,这个是子类重写父类的方法
  set contrast(num value) {}
}
Code language: JavaScript (javascript)

3. 重写必须遵守的规则

  1. 返回值类型:重写方法返回类型 必须和父类方法返回类型一致,或是其父类返回类型的子类型
  2. 参数类型:重写方法参数类型 必须和父类参数类型一致,或是父类参数类型的父类型(示例中 intnum,num 是 int 的父类型,合法)。
  3. 位置参数数量:若被重写方法拥有 n 个位置参数,重写方法也必须拥有 n 个位置参数。
  4. 泛型约束:泛型方法不能重写非泛型方法;非泛型方法不能重写泛型方法。

4. covariant 关键字(类型收窄特殊场景)

正常规则不允许缩小参数类型(向下转型,运行时可能触发类型错误);

如果开发者可以保证不会产生类型错误,可以在参数上标记 covariant,实现参数类型收窄。

如果你重写运算符 ==必须同时重写 ObjecthashCode getter


noSuchMethod ()

1. 作用

当代码尝试调用不存在的实例方法 / 实例变量时,可重写 noSuchMethod() 进行捕获、自定义处理。

不重写时,访问不存在成员会直接抛出 NoSuchMethodError

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
  }
}
Code language: JavaScript (javascript)
  • Invocation 对象:保存本次调用信息(成员名称、参数等)
2. 能够调用未实现方法的两个前提(满足其一)
  1. 调用接收者的静态类型为 dynamic
  2. 接收者静态类型声明了该未实现方法(可以是抽象方法),并且接收者的动态类型拥有和 Object 内置版本不同的 noSuchMethod() 实现。

例子

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
    // 额外打印调用参数、调用类型,展示完整调用信息
    print('调用参数:${invocation.arguments}');
    print('调用类型:${invocation.runtimeType}');
  }
}

void main() {
  A obj = A();
  // 调用不存在的方法,触发 noSuchMethod
  obj.hello("test", 123);
  // 访问不存在属性
  obj.unknownValue;
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:6:30: Error: The getter 'arguments' isn't defined for the type 'Invocation'.
 - 'Invocation' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'arguments'.
    print('cal:${invocation.arguments}');
                             ^^^^^^^^^
bin/firstdart.dart:14:7: Error: The method 'hello' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing method, or defining a method named 'hello'.
  obj.hello("test", 123);
      ^^^^^
bin/firstdart.dart:16:7: Error: The getter 'unknownValue' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'unknownValue'.
  obj.unknownValue;Code language: PHP (php)

Next:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注