0%

Dart学习笔记 (七)

静态成员和非静态成员 , 对象操作符 , 类的继承 , 子类覆写 , 抽象类 , 接口 , 一个类实现多个接口 , Dart中的Mixins

Dart中的静态成员与非静态成员

  • 使用static 关键词可定义静态属性静态方法

  • 静态方法不能访问非静态成员,非静态方法可以访问静态成员

  • 类中非静态方法和属性必须实例化后访问,静态成员可以不用实例化也能访问

    例1:静态成员与非静态成员

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Person{
    static String name='张三'; //静态属性
    int age=20; //非静态属性
    static void show(){ //静态方法
    print(name); //静态方法调用静态属性
    }
    void printInfo(){ //非静态方法
    print(name); //非静态方法调用静态属性
    print(age); //非静态方法调用非静态属性
    show(); //非静态方法调用静态方法
    }
    }
    main(){
    Person p=Person(); //因有非静态成员所以要实例化
    print(Person.name); //静态成员可不用实例化直接调用 输出: 张三
    Person.show(); //也可实例化之后调用 输出: 张三
    p.printInfo(); //非静态成员必须实例化后调用 输出: 张三 20 张三
    }

对象操作符

  • Dart中的对象操作符有:

    ?条件运算符(了解) , as类型转换符 , is类型判定符 , ..级联操作符(连缀)

  • 连缀的第一行不要添加分号,最后一行再加,可以省略相同的开头

    例1:连缀的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import 'lib/person.dart';              //调用Person类
    main(){
    Person p=Person('张三', 20); //实例化Person类
    p.getInfo(); //输出: 姓名:张三 年龄:20
    p.name='李四';
    p.age=40;
    p.getInfo(); //输出: 姓名:李四 年龄:40
    }
    //可使用级联操作符进行简化
    import 'lib/person.dart'; //调用Person类
    main(){
    Person p=Person('张三', 20); //实例化Person类
    p..getInfo() //输出: 姓名:张三 年龄:20
    ..name='李四'
    ..age=40
    ..getInfo(); //输出: 姓名:李四 年龄:40
    }

类的继承

  • 子类可通过extends关键词来继承父类

  • 子类会继承父类里可见的属性和方法,但不会继承构造函数

  • 子类能覆写父类的方法和getter , setter

  • 使用super关键词还可以给父类的命名构造函数传参

    例1:子类继承父类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Person{
    String name;
    int age;
    Person(this.name,this.age);
    getInfo(){
    print('$name,$age');
    }
    }
    class Web extends Person{ //子类继承父类
    Web(String name, int age,String sex) : super(name, age){ //子类构造函数,super是吧子类实例化时的数据赋给父类
    this.sex=sex; //子类自己的属性赋予实例化关联
    }
    String sex; //子类可以定义自己的属性
    void run(){ //子类可以定义自己的方法
    print('姓名:$name 性别:$sex 年龄:$age');
    }
    }
    main(){
    var p=Person('张三', 20); //我们这里首先实例化了父类为p
    p.getInfo(); //p输出: 张三,20
    var w=Web('李四', 25, '女'); //随后实例化了子类为w
    w.getInfo(); //子类可以调用父类的方法和属性,因为在实例化w的同时吧w实例化赋予的数据通过super传给了父类,所以这里调用父类的方法输出的是: 李四,25
    w.run(); //子类可以调用自己的方法 输出: 姓名:李四 性别:女 年龄:25
    p.getInfo(); //父类调用父类的方法,因为P实例化时传入数据是张三和20,这里输出的是p不是w不受子类传输的数据影响,所以输出依旧是: 张三,20
    }

    例2:使用super关键词还可以给父类的命名构造函数传参

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Person.now(this.name,this.age){
    print(DateTime.now());
    }
    //例如Person有一个Person.now的构造函数
    Web.now(String name, int age,String sex) : super.now(name, age){
    this.sex=sex;
    }
    //则继承之后再子类中也可以添加一个super.now的构造函数,实例化调用时也可以
    var w=Web.now('李四', 25, '女');

子类覆写父类的方法

  • 覆写就是在子类中使用和父类里同样名字的方法来重写方法

  • 实例化子类后调用此方法时默认调用覆写后的方法

    例1:覆写父类的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Person{
    String name;
    Person(this.name);
    run(){
    print(name); //父类方法
    }
    }
    class Web extends Person{

    String sex;
    Web(String name,String sex) : super(name){
    this.sex=sex;
    }
    @override //覆写方法时点击方法名点修复会自动显示,也可以手动输入,@override可以判断覆写方法名和父类方法名是否完全一致,不一致的话会报错
    void run(){
    print('姓名:$name 性别:$sex,正在打扫卫生'); //覆写的方法,在子类调用此方法时会优先调用子类覆写的方法
    }
    }
    main(){
    var w=Web('张三', '女');
    w.run(); //调用子类的run方法输出: 姓名:张三 性别:女,正在打扫卫生
    }
  • 使用super关键词可在子类的方法中调用父类的方法

    例2:在子类中调用父类方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class Person{
    String name;
    Person(this.name);
    run(){
    print(name);
    }
    work(){
    print('正在工作中...'); //父类中方法work
    }
    }
    class Web extends Person{

    String sex;
    Web(String name,String sex) : super(name){
    this.sex=sex;
    }
    @override
    void run(){
    print('姓名:$name 性别:$sex,正在打扫卫生');
    super.work(); //在子类的方法中使用super.work来调用父类的方法
    //work(); 可能是新版本的原因,似乎在Dart中现在不用super关键词也可以直接在子类中调用父类方法
    }

    }
    main(){
    var w=Web('张三', '女');
    w.run(); //输出: 姓名:张三 性别:女,正在打扫卫生
    // 正在工作中...
    }

抽象类

  • Dart中的抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口

  • 抽象类通过obstract关键词定义(声明)

  • Dart中的抽象方法不能用obstract声明,Dart中没有方法体的方法,我们称之为抽象方法

  • 如果子类继承抽象类,那么必须要实现抽象类中的抽象方法

  • 如果吧抽象类当做接口实现的话,必须要实现抽象类里定义的所有属性和方法

  • 抽象类不可以实例化,只有继承它的子类可以实例化

  • 多态的定义

    • 多态就是父类定义的一个方法不实现,让继承他的子类实现,每个子类有不同的表现
    • 子类继承父类抽象类的时候也可以有自己的普通方法,但如果想在实例化后只能调用父类的抽象类而不能用自己的普通类,可以吧子类的实例赋值给父类的引用,这就是普通意义上的多态(例2)

    例1:定义一个抽象类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    abstract class Animal{                     //抽象类,不可实例化
    eat(); //抽象方法,子类必须实现
    run();
    printInfo(){ //抽象类中可以有一般方法
    print('我是一个抽象类中的普通方法');
    }
    }
    class Dog extends Animal{ //子类继承抽象类
    @override
    eat(){ //子类覆写并实现父类的抽象方法
    print('小狗吃骨头');
    }
    @override
    run(){
    print('小狗RushB');
    }
    }
    class Cat extends Animal{
    @override
    eat(){
    print('小猫吃老鼠');
    }
    @override
    run(){
    print('小猫RushB');
    }
    }
    main(){
    Dog d=Dog(); //实例化子类,抽象类不可实例化
    d.eat(); //输出: 小狗吃骨头
    d.printInfo(); //输出: 我是一个抽象类中的普通方法
    Cat c=Cat(); //多态的一种
    c.eat(); //输出: 小猫吃老鼠
    c.run(); //输出: 小猫RushB
    }

    例2:把子类的实例赋值给父类的引用

    1
    2
    3
    //在实例化时,吧子类的实例赋值给父类的引用
    Animal d=Dog();
    //这时候就只能调用Animal中的方法,不能调用Dog中的方法了

接口

  • Dart的接口没有interface关键字定义接口,而是普通类或抽象类都哦可以作为接口被实现,但和其他语言一样同样使用implements关键词进行实现

  • extends抽象类和implements的区别:

    • 如果要使用抽象类里面的方法,并且要用抽象方法约束子类的话我们就用extends方法继承抽象类
    • 如果只是吧抽象类当做标准的话,我们就用implements实现抽象类
  • 如果实现的类是普通类,会将普通类或抽象类中的属性和方法全部覆写一遍

  • 因为抽象类可以定义抽象方法,普通类不可以,所以如果要实现接口,一般会使用抽象类定义接口

    例1:定义一个DB库,支持mysql , mssql , mongodb

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    abstract class Db{                     //当做接口,接口就是约定/规范
    String url; //数据库的链接地址
    add(date);
    save();
    delete();
    }
    class Mysql implements Db{
    @override
    String url;
    Mysql(this.url); //接口拥有自己的构造函数
    @override
    add(date) {
    print('这是mysql的add方法$date');
    }
    @override
    delete() {
    }
    @override
    save() {
    }
    }
    class Mssql implements Db{
    @override
    String url;
    @override
    add(date) {
    }
    @override
    delete() {
    }
    @override
    save() {
    }
    }
    class Mongodb implements Db{
    @override
    String url;

    @override
    add(date) {
    }
    @override
    delete() {
    }
    @override
    save() {
    }
    }
    main() {
    var mysql=Mysql('xxx');
    mysql.add('123ddas'); //输出: 这是mysql的add方法123ddas
    }
    //一般情况下接口和方法会被抽离到单独文件,然后调用

一个类实现多个接口

  • 一个类可通过implements关键词来实现多个接口,但同时要实现多个接口里所有的属性和方法

  • extends继承并不能同时实现多个接口

    例1:定义两个接口,然后用一个来同时实现两个接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    abstract class A{
    printA();
    String name;
    }
    abstract class B{
    printB();
    }
    class C implements A,B{ //C类同时实现A和B两个接口
    @override
    String name; //必须同时实现两个类里所有的方法和属性
    @override
    printA() {
    print('A方法');
    }
    @override
    printB() {
    print(name);
    }
    }
    main() {
    var c=C(); //实例化C类后可调用里面所有的方法和属性
    c.name='张三';
    c.printA(); //输出: A方法
    c.printB(); //输出: 张三
    }

Dart中的Mixins(混入)

  • 在Dart中可以使用mixinswith关键词实现类似多继承的功能

  • 作为mixins的类只能继承自object,不能继承其他类

    • 指C如果要mixins A和B,则A和B必须是一个类,而不是继承自其他类的子类
  • 作为mixins的类不能有构造函数

  • 一个类可以mixins多个mixins类

  • mixins绝不是继承,也不是接口,而是一种全新的特性

  • 如果实例化后要调用的方法在几个类中都有同名方法,则以with关键词后最后的类覆盖前面的类(例3)

    例1:使用mixins的with关键词实现类似多继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class A{                    //被mixins的类中不能有构造函数
    printA(){
    print('A');
    }
    run(){
    print('A Run');
    }
    }
    class B{
    printB(){
    print('B');
    }
    run(){
    print('B Run');
    }
    }
    class C with B,A{ //C with B和A

    }
    main(){
    var c=C();
    c.printB(); //输出: B
    c.printA(); //输出: A
    }

    例2:一个类可以mixins多个mixins类,有两种方法,第一种直接mixins

    1
    2
    3
    class C with Person,B,A{

    }

    例3:第二种方法则可以首先使用C继承Person再mixins A和B 则父类Person中可以拥有构造函数,C中也要覆写Person的构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    class Person{
    String name;
    num age;
    Person(this.name,this.age);
    printInfo(){
    print('$name,$age');
    }
    run(){
    print('Person Run');
    }
    }
    class A{
    printA(){
    print('A');
    }
    run(){
    print('A Run');
    }
    }
    class B{
    printB(){
    print('B');
    }
    run(){
    print('B Run');
    }
    }
    class C extends Person with B,A{ //可继承Person然后再WithB和A,则可以拥有Person的构造函数
    C(String name, num age) : super(name, age);

    }
    main(){
    var c=C('张三',20); //实例化时要传参
    c.run(); //因为class C extends Person with B,A按顺序A在最后面,后面的覆盖前面的,所以输出: A Run
    c.printA(); //输出: A
    c.printInfo(); //这里调用了Person类父类的方法 输出: 张三,20
    }
-------------本文有底学海无涯-------------