2026/1/27 17:14:03
网站建设
项目流程
青岛专用网站制作,移动app与网站建设的区别,网站平台建设十大公司,南京企业网站设计建设序言
在dart中#xff0c;允许多种形式的构造方法#xff0c;上篇类中#xff0c;也有涉略。在这篇文章中我们进行深入的学习。
构造 方法的类型
Generative constructors、Default constructors、Named constructors、Constant constructors、Redirecting constructors、Fa…序言在dart中允许多种形式的构造方法上篇类中也有涉略。在这篇文章中我们进行深入的学习。构造 方法的类型Generative constructors、Default constructors、Named constructors、Constant constructors、Redirecting constructors、Factory constructors、Redirecting factory constructors以及Constructor tear-offs这些都是官方文档中给到的构造方法的类型下面我们逐一了解Generative constructors是一种类似java的构造函数基础的classPoint{// Instance variables to hold the coordinates of the point.double x;double y;// Generative constructor with initializing formal parameters:Point(this.x,this.y);}Default constructors默认构造当你没有明确声明构造方法时就会使用这个Named constructors命名构造当你给构造函数起了一个其他名字时就是命名构造但命名必须遵循class.name的形式如下constdouble xOrigin0;constdouble yOrigin0;classPoint{finaldouble x;finaldouble y;// Sets the x and y instance variables// before the constructor body runs.Point(this.x,this.y);// Named constructorPoint.origin():xxOrigin,yyOrigin;}子类不会继承父类的命名构造Constant constructors如果类生成不变的对象将这些对象设置为编译时常量。要使对象成为编译时常量定义一个const构造函数并将所有实例变量设置为final。classImmutablePoint{staticconstImmutablePoint originImmutablePoint(0,0);finaldouble x,y;constImmutablePoint(this.x,this.y);}常量构造函数并不总是创建常量。它们可以在非常量上下文中调用。如下voidmain(){constImmutablePoint pImmutablePoint(10,20);varp1constImmutablePoint(10,20);varp2ImmutablePoint(10,20);//这个叫非常量上下文print(pp1);//trueprint(pp2);//falseprint(p1p2);//false}classImmutablePoint{staticconstImmutablePoint originImmutablePoint(0,0);finaldouble x,y;constImmutablePoint(this.x,this.y);}Redirecting constructors构造函数可以重定向到同一个类中的另一个构造函数。重定向构造函数有一个空主体。构造函数使用this代替冒号:后面的类名。classPoint{double x,y;// The main constructor for this class.Point(this.x,this.y);// Delegates to the main constructor.Point.alongXAxis(double x):this(x,0);}Factory constructors这个上篇文章也讲到了当遇到下列两种实现构造函数的情况之一时请使用factory关键字构造函数并不总是创建类的新实例。尽管工厂构造函数不能返回null但它可能返回从缓存中创建一个现有实例而不是创建一个新的实例 子类型的新实例在构建实例之前你需要执行一些重要的工作。这可能包括检查参数或进行任何在初始化列表中无法处理的其他处理。varloggerLogger(UI);logger.log(Button clicked);varlogMap{name:UI};varloggerJsonLogger.fromJson(logMap);classLogger{finalString name;bool mutefalse;// _cache is library-private, thanks to// the _ in front of its name.staticfinalMapString,Logger_cacheString,Logger{};factoryLogger(String name){return_cache.putIfAbsent(name,()Logger._internal(name));}factoryLogger.fromJson(MapString,Objectjson){returnLogger(json[name].toString());}Logger._internal(this.name);voidlog(String msg){if(!mute)print(msg);}}工厂构造不能访问thisRedirecting factory constructors有了上面的经验这个也不难理解了factoryListenable.merge(ListListenablelistenables)_MergingListenable普通的工厂构造函数似乎可以创建和返回其他类的实例。这将使重定向工厂变得不必要。重定向工厂有几个优点抽象类可能会提供一个使用另一个类的常量构造函数的常量构造函数。重定向工厂构造函数避免了转发器重复形式参数及其默认值的需要。Constructor tear-offs支持撕开看下面的例子finalListintcharCodes[72,101,108,108,111,33];// Hello!// Use a tear-off for a named constructor:varstringscharCodes.map(String.fromCharCode);// Use a tear-off for an unnamed constructor:varbufferscharCodes.map(StringBuffer.new);上面的代码中使用了lamada去除后如下// Instead of a lambda for a named constructor:varstringscharCodes.map((code)String.fromCharCode(code));// Instead of a lambda for an unnamed constructor:varbufferscharCodes.map((code)StringBuffer(code));Instance variable initialization 实例变量初始化dart中有3种变量初始化方式Initialize instance variables in the declaration声明时初始化classPointA{double x1.0;double y2.0;// The implicit default constructor sets these variables to (1.0,2.0)// PointA();overrideStringtoString(){returnPointA($x,$y);}}Use initializing formal parameters使用初始化形式参数初始化参数也可以是可选的classPointB{finaldouble x;finaldouble y;// Sets the x and y instance variables// before the constructor body runs.PointB(this.x,this.y);// 初始化参数也可以是可选参数PointB.optional([this.x0.0,this.y0.0]);}私有字段不能用作命名初始化形式变量。可以使用下面的方式classPointB{// ...PointB.namedPrivate({required double x,required double y}):_xx,_yy;// ...}上面的写法也适用于命名变量classPointC{double x;// must be set in constructordouble y;// must be set in constructor// Generative constructor with initializing formal parameters// with default valuesPointC.named({this.x1.0,this.y1.0});overrideStringtoString(){returnPointC.named($x,$y);}}// Constructor using named variables.finalpointCPointC.named(x:2.0,y:2.0);所有通过初始化形式参数引入的变量都是final变量并且只在初始化变量的作用域内。要执行无法在初始化列表中表达的逻辑请使用该逻辑创建工厂构造函数或静态方法。然后您可以将计算值传递给普通构造函数。构造函数的参数可以声明为可空类型并且可以被初始化或不被初始化classPointD{double?x;// null if not set in constructordouble?y;// null if not set in constructor// Generative constructor with initializing formal parametersPointD(this.x,this.y);overrideStringtoString(){returnPointD($x,$y);}}Use an initializer list使用初始化列表在运行构造函数体之前可以初始化实例变量。用逗号分隔初始化方法。// Initializer list sets instance variables before// the constructor body runs.Point.fromJson(MapString,doublejson):xjson[x]!,yjson[y]!{print(In Point.fromJson(): ($x, $y));}初始化列表的右侧不能访问this在开发期间可以通过初始话列表使用assert验证输入参数Point.withAssert(this.x,this.y):assert(x0){print(In Point.withAssert(): ($x, $y));}初始化列表也可以用来设置final值如下classA{finalint x;// A(this.x);A(int u):xu;}Constructor inheritance构造函数的继承子类不会从超类或直接父类继承构造方法。如果类没有声明构造方法那么只能使用默认的构造方法。类可以继承超类的参数。这些称为超参数super parameter构造函数的工作方式与调用静态方法链的方式有些类似。每个子类都可以调用超类的构造函数来初始化实例就像子类调用超类的静态方法一样。这个过程不会“继承”构造函数体或签名。Non-default superclass constructors非默认超类构造Dart按以下顺序执行构造函数初始化器列表超类的未命名、无参数的构造函数主类的无参数构造函数如果超类没有未命名的、无参数的构造方法就调用超类中的一个构造方法。在构造函数主体之前如果有的话在冒号:之后指定超类的构造函数。classPerson{String?firstName;Person.fromJson(Map data){print(in Person);}}classEmployeeextendsPerson{// Person does not have a default constructor;// you must call super.fromJson().Employee.fromJson(Map data):super.fromJson(data){print(in Employee);}}由于Dart在调用构造函数之前计算超类构造函数的参数因此参数可以是类似于函数调用的表达式classEmployeeextendsPerson{Employee():super.fromJson(fetchDefaultData());// ···}超类构造函数的参数无法访问this。例如参数可以调用静态方法但不能调用实例方法Super parameters为了避免将每个参数都传入构造函数的父类调用中可以使用 super-initializer 参数超类初始化参数将参数直接转发到指定或默认的父类构造函数。此功能不能与重定向构造函数一起使用。classDogextendsAnimal{finalString breed;// 传统方式需要将 name 手动传递给 superDog(String name,this.breed):super(name);}classDogextendsAnimal{finalString breed;// 新方式使用 super-initializer 参数Dog(super.name,this.breed);// ↑ super.name 自动将 name 参数转发给父类 Animal 构造函数}下面是个错误案例Vector3d.xAxisError(super.x):z0,super(0);// BAD这个命名构造函数试图设置x的值两次一次是在super构造函数中另一次是作为位置超参数。因为它们都指向位置参数x所以会导致错误。当超类构造函数有命名参数时你可以将它们分配到命名的 super 参数如下例中的 super.y超类构造函数调用中的命名参数如 super.named(x: 0)classVector2d{// ...Vector2d.named({requiredthis.x,requiredthis.y});}classVector3dextendsVector2d{finaldouble z;// Forward the y parameter to the named super constructor like:// Vector3d.yzPlane({required double y, required this.z})// : super.named(x: 0, y: y);Vector3d.yzPlane({requiredsuper.y,requiredthis.z}):super.named(x:0);}小结太灵活了