Classes - ShenYj/ShenYj.github.io GitHub Wiki

Classes

Dart是一种面向对象的语言,具有类和基于混合的继承。每个对象都是一个类的实例,除Null外,所有类都从Object下降。基于混合的继承意味着尽管每个类(除了顶级类,对象?)恰好有一个超类,一个类主体可以在多个类层次结构中重用。扩展方法是一种在不更改类或创建子类的情况下向类添加功能的方法。类修饰符允许您控制库如何子类型类。

参考资料: Dart: Classes

与大多数编程语言一样,类的实例通过.语法访问成员属性和成员方法

类的基本使用

定义一个类

简单定义一个类,包含年龄和姓名两个属性和一个输出信息的方法

成员变量以_开头表示私有 (如果在同一文件内,仍然是可以访问的)

class Person {
    String name = '张三';
    int age = 23;

    void printInfo() {
        print("age--->:$age");
        print("name---->:${this.name}");
    }

    void setAge(int age) {
        this.age = age;
    }
}

/// new 可以省略
var p = new Person();
Person p1 = new Person();

p.printInfo();
p1.setAge(28);
  • 当最左边的操作数为空时,使用?.而不是.来避免异常:

    class Person {
        int age;
    }
    
    Person p1;
    Person p2 = new Person();
    
    p1?.age; /// 使用 ?. 来避免异常
    p2.age;

构造函数

如果不声明构造函数,Dart将使用默认构造函数。默认构造函数是没有参数或名称的生成构造函数。

class Person {
    /// 实例化的时候自动触发构造函数
    Person() {
        
    }
}

自定义构造函数,比如实例化时为属性赋值

class Person {
    String name;
    int age;
    /// 实例化的时候赋值
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

var p = Person('zhang', 10);

上面的初始化赋值还可以简写为

class Person {
    String name;
    int age;
    /// 构造函数简写
    Person(this.name, this.age);
}
var p = Person('zhang', 10);

命名构造函数

dart 中默认构造函数只能存在一个,命名构造函数可以存在多个

有点类似于自定义构造函数、便利构造函数,只是语法糖不同

格式: 类名.定义的匿名函数名称() { ... }

class Person {
    String name;
    int age;
    
    /// 默认构造函数
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /// 匿名构造函数
    Person.now() {
        print('命名构造函数');
    }
}

var p = Person.now();

参考资料: Dart: Constructors - Named constructors

常量构造函数

  1. 常量构造函数需要以const关键字修饰
  2. const构造函数必须用于成员变量都是final的类
  3. 如果实例化时不加const修饰符,即使调用的是常量构造函数,实例化的对象也不是常量实例
  4. 实例化常量构造函数的时候,多个地方创建这个对象,如果传入的值相同,只会保留一个对象
  5. Flutter中const修饰不仅仅是节省组件构建时的内存开销, Flutter 在需要重新构建组件的时候,不重新构建const组件
class Container {

    final int width;
    final int height;

    const Container({required this.width, required this.height});
}

/// 不是常量实例对象: 调用构造函数时没有添加 const关键字
var c1 = Container({
    width: 10,
    height: 20
});
/// 常量实例对象
var c2 = const Container({
    width: 10,
    height: 20
});

参考资料: Dart: Constructors - Constant constructors

获取对象的类型

要在运行时获取对象的类型,您可以使用 Object属性runtimeType,该属性返回 Type对象。

print('The type of a is ${a.runtimeType}');

Getters and setters

Getters和setters是提供对对象属性的读写访问权限的特殊方法。回想一下,每个实例变量都有一个隐式获取器,如果合适,还有一个设置器。您可以使用get和set关键字,通过实现getters和setters来创建其他属性

  • 利用命名函数实现计算面积的功能

    class Rect {
        num height;
        num width;
        Rect(this.height, this.width);
        Rect.area() {
            return this.height * this.width;
        }
    }
    
    var area = Rect.area();
    print('面积: ${area}')    
  • 利用getter 实现同样功能

    class Rect {
        num height;
        num width;
        Rect(this.height, this.width);
        /// getter
        get area {
            return this.height * this.width;
        }
    }
    
    var r = Rect(20, 10);
    print('面积: ${r.area}')
    

    类似于计算属性, 没有 ()

  • setter的使用

    class Rect {
        num height;
        num width;
        Rect(this.height, this.width);
        /// getter
        get area {
            return this.height * this.width;
        }
        /// setter
        set areaHeight(int height) {
            this.height = height
        }
    }

参考资料: Dart: Methods - Getters and setters

初始化列表

类似于 C++初始化列表, dart 也提供了这种语法糖,语法有少许区别

在构造函数体运行之前,可以初始化实例变量。用逗号分隔初始化器。

class Person {
    String name;
    int age;
    /// 构造函数简写
    Person(): height = 2, width = 10 {

    }
}

通过传入参数赋值

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, double> json)
    : x = json['x']!,
      y = json['y']! {
  print('In Point.fromJson(): ($x, $y)');
}

初始化列表配合断言

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}

参考资料: Dart: Constructors - User an initializer list

静态成员

同样使用 static 关键字实现全类变量和方法。
同样静态方法不能访问非静态成员,非静态方法可以访问静态成员

Static variables

静态变量(类变量)对全类状态和常量很有用

class Person {
    static String name = '张三';
}

Person.name;

Static methods

静态方法(类方法)

class Person {
    static void show() { };
}

Person.show();

级联操作

也叫连缀操作

下面两种使用效果一致

class Person {
    int age;
    String name;

    void printInfo() {

    }
}

Person p1 = new Person();
p1.name = '张三';
p1.age = 20;
p1.printInfo();

Person p2 = new Person();
p2..name = '张三'
  ..age = 20
  ..printInfo();

继承

  1. dart 中使用 extends 关键字来实现继承
  2. 子类汇继承父类里面可见的属性和方法,但是不会继承构造函数
  3. 子类能重写父类的方法 getter和setter
  • 继承的基本实现

    class Person {
    
    }
    
    class Student extends Person {
    
    }
  • 重写父类方法

    class Television {
        // ···
        set contrast(int value) {...}
    }
    
    class SmartTelevision extends Television {
        /// `override` 可写可不写
        @override
        set contrast(num value) {...}
        // ···
    }
  • 实例化子类时,使用super为父类属性赋值

    class Person {
        int age;
        String name;
        Person(this.age, this.name);
    }
    
    class Student extends Person {
        /// 利用初始化列表 
        Student(String name, int age): super(age, name)
    }
  • 实例化子类时,给命名构造函数传参

    class Person {
        int age;
        String name;
        Person(this.age, this.name);
        /// 命名构造函数
        Person.create(this.age, this.age);
    }
    
    class Student extends Person {
        /// 这里在构造 Student的时候,调用的是命名构造函数初始化父类的属性
        Student(int age, String name): create(age, name);
    
    }

参考资料: Dart: Classess & Object - Extend a class

多态

允许将子类子类的指针赋值给父类类型的指针,同一个函数调用会有不同的执行效果
子类的实例赋值给父类的引用
多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。

抽象类

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

  1. 抽象类通过 abstract 关键字定义
  2. Dart中的抽象方法不能用 abstract 声明, dart 中没有方法体的方法我们称为抽象方法
  3. 如果子类继承抽象类必须得实现里面的抽象方法
  4. 如果吧抽象类当做借口实现的话,必须要实现抽象类里面定义的所以属性和方法

extends 抽象类 和 implements 的区别

  1. 如果要复用抽象类里面的方法,并且要用抽象方法约束子类的话,用extends继承抽象类
  2. 如果只是把抽象类当做标准,用implements实现抽象类
  • 示例: 定义一个 Animal 类要求它的子类必须包含 eat 方法

    abstract class Animal {
        /// 抽象方法
        eat();
    }
    
    class Dog extends Animal {
        @override
        eat() {  }
    }
  • implements 示例

    absctact class DB {
        add();
        save();
        delete();
    }
    
    class Mysql implements Db {
    
        @override
        add() { }
        
        @override
        save() { }
    
        @override
        delete() { }
    }
  • 一个类实现多个接口

    abstract class A {
        String name;
        printA();
    }
    
    abstract class B {
        printB();
    }
    
    class c implements A, B {
    
        @override
        String name;
    
        @override
        printA() { }
    
        @override
        printB() { }
    }

参考资料

⚠️ **GitHub.com Fallback** ⚠️