dart构造函数解析

一 构造函数格式

  • ClassName() 默认构造函数
  • ClassName(…) 普通构造函数(无名或无参)
  • ClassName.identifier() 命名构造函数(有参或无参)
  • const ClassName(…) 常量构造函数
  • factory ClassName(…) 工厂构造函数

二 构造函数定义和使用

2.1 默认构造函数

如果定义了一个类,在没有自定义其他构造函数的前提下,那么该类会有一个默认的构造函数,并且该函数没有名称也没有参数
tips: 如果自定义了任何形式的构造函数,那么不会生成默认构造函数。

class Animal {
  double weight;
  double height;
}

void main() {
  Animal animal = Animal(); // 调用默认构造函数
  animal.height = 180;
  animal.weight = 100;
}

2.2 普通构造函数

普通构造函数也没有函数名,可以定义参数或者无参数。

tips: 显式定义的无参普通构造函数和默认的构造函数形式一样。这里主要在继承时需要注意一下,下面的继承段落会阐述。

使用如下:

class Animal {
  double weight;
  double height;
  
/// 定义普通构造函数
  Animal(double weight, double height) {
    this.weight = weight;
    this.height = height;
  }
}

void main() {
  Animal animal = Animal(100, 180);
}

如果类有多个成员变量,那么使用 this.ivar = value的形式显得很繁琐,所以dart提供了语法糖,使用如下:

class Animal {
  double weight;
  double height;

  Animal(this.weight, this.height);
}

void main() {
  Animal animal = Animal(100, 180);
}

2.3 命名构造函数

指定函数名称,然后可以添加参数或者无参数,也可以使用上述的语法糖,使用如下:

class Animal {
  double weight;
  double height;

  Animal.initial(this.weight, this.height);
}


void main() {
  Animal animal = Animal.initial(100, 180);
}

2.4 常量构造函数

如果你希望你的实例对象创建出来后是不可改变的,那么可以定一个常量构造函数,在编译期就创建这个常量实例。

需要注意的点:

  • 全部的成员变量必须是final修饰的。
  • 构造函数前使用const进行修饰。

使用如下:
:为了确保创建的常量实例不可变,在调用时可以使用const进行修饰。

class Animal {
  final double weight;
  final double height;
  
  /// 使用const进行修饰
  const Animal(this.weight, this.height);
}

void main() {
 const Animal animal = Animal(100, 180);
}

2.5 工厂构造函数

工厂构造函数的定义为每一次调用构造函数时,并不是都新建一个实例对象。

常用场景:

  • 返回已经存在的对象。
  • 创建单例。
  • 用于返回指定的子类对象。
1.dart官方文档中的举例:
class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

main() {
    var logger = Logger('UI');
    logger.log('Button clicked');
}

工厂构造函数根据传入的namekey,从_cache中寻找,如果有对应_key,则返回对应的logger对象。如果没有的话,则调用私有命名构造函数 Logger_internal(this.name)

2.用于单例的创建

使用如下:

class Animal {
  Animal._initial();
  static final Animal _instance = Animal._initial();

  factory Animal() {
    return _instance;
  }
}

void main() {
  /// animal为单例对象
  Animal animal = Animal();
}

2.6 构造函数的传递

构造函数可以进行传递,直接在小括号后面使用":",然后使用this调用其他的构造函数。

使用如下:

class Animal {
  Animal.initial() {
    print('animal inital');
  }

  Animal.create() : this.initial();
}

main() {
  Animal animal = Animal.create();
}

/// print result: animal inital

三 构造函数在继承中的使用

3.1 继承中构造函数使用规则

规则如下:

  • 子类只能继承父类的无名无参构造函数(包含默认构造函数或者是自定义的无名无参构造函数)。
  • 子类的构造函数中必须调用父类的构造函数。

dart默认帮子类自动调用父类的无名无参构造函数。
自定手动调用父类的构造函数。

3.1.1. 无名无参构造函数的继承与调用

父类有默认构造函数或者自定义了无名无参构造函数时,子类会自动继承父类的无名无参构造函数。

并且在子类调用任何形式的构造函数时,都会自动调用父类的无名无参构造函数。

父类没有自定义构造函数时:

class Animal {}

class Dog extends Animal {
  Dog() {
    print('dog');
  }
}

main() {
  Dog dog = Dog();
}

///print result: dog

因为子类必须调用父类的构造函数,所以这里是自动调用了父类的默认构造函数。
父类自定义了无名无参构造函数时:

class Animal {
/// 自定义无名无参构造函数
  Animal() {
    print('animal');
  }
  
/// 自定义命名构造函数
  Animal.initial() {
    print('animal initial');
  }
}

class Dog extends Animal {
  Dog() {
    print('dog');
  }
}

main() {
  Dog dog = Dog();
}

/// print result: animal
/// print result: dog

父类存在无名无参构造函数,子类调用其他构造函数时:

class Animal {
  Animal() {
    print('animal');
  }

  Animal.initial() {
    print('animal initial');
  }
}

class Dog extends Animal {
  Dog.initial() {
    print('dog initial');
  }
}

main() {
  Dog dog = Dog.initial();
}

/// print result: animal
/// print result: dog initial
3.1.2 子类手动调用父类的构造函数

这里需要提到一个初始化列表,这里仅简单的介绍。

子类在调用构造函数时的顺序是:

  • 初始化列表
  • 父类的构造函数
  • 子类的构造函数

子类手动调用父类的构造函数就是需要在初始化列表中调用,格式为构造函数小括号后添加分号":" ,然后使用super调用。

使用如下:

class Animal {
  Animal.initial() {
    print('animal initial');
  }

  Animal.create() {
    print('animal create');
  }
}

class Dog extends Animal {
  Dog() : super.initial();

  Dog.initial() : super.create();
}

main() {
  Dog dog1 = Dog();  /// print result: animal initial
  Dog dog2 = Dog.initial(); /// print result: animal create
}

3.2 初始化列表

初始化列表执行在构造函数之前,除了可以调用父类的构造函数之外,还可以初始化一些成员变量。初始化成员变量和调用父类的构造函数之间使用逗号","分隔。

特别是对于final修饰的成员变量,final变量在构造函数中是已经不能进行修改的。那么就可以在初始化列表中进行初始化。

使用如下:

class Animal {
  final double height;
  final double weight;

  Animal.initial(double weight, double height)
      : height = height,
        weight = weight {
    print('animal initial');
  }
}

main() {
  Animal animal = Animal.initial(100, 180);
}

初始化列表中还可以进行性aseert添加判断等应用。
后续文章中进行详细的记录。

你可能感兴趣的:(flutter,dart,flutter)