浅谈 Dart 类与类的基本方法 您所在的位置:网站首页 dart类型判断 浅谈 Dart 类与类的基本方法

浅谈 Dart 类与类的基本方法

2023-10-13 22:18| 来源: 网络整理| 查看: 265

一、Dart 语言

Dart 是一门面向对象的语言。

Dart 语言中所有的变量引用都是一个对象,并且所有的对象都对应一个类的实例。无论是数字、函数和null ,都是一个对象,所有对象继承自Object类。在 2.12 版本 Dart 新增空安全后(sound null safety),null不再是Object的子类。

Object

Object 具有下列特性:

两个属性:hashCode和runtimeType; 两个方法:noSuchMethod和toString; 操作符:Operator hashCode

hashCode 是 read-only 属性的 int 类型数据,因为 Dart 所有的变量引用均继承于Object,所以每个变量引用都有自己的hashCode。hashCode的设计目的是为了提高 Dart VM 引擎在解析数据结构时的效率,并且参与判断对象的逻辑运算,与操作符 operator 相辅相成。考察如下代码:

void main() { P p1 = P("yo","no"); P p2 = P("yo","no"); print(p1 == p2); print(p1.hashCode); print(p2.hashCode); Map myMap = {}; myMap[p1] = "first Item"; print(myMap.containsKey(p2)); } class P { var naam; var kaam; P(this.naam, this.kaam); @override int get hashCode { int result = 11 * naam.hashCode; result = 13 * (result + kaam.hashCode); return result; } @override bool operator == (dynamic otherObj) { return (otherObj is P) && (otherObj.naam == naam) && (otherObj.kaam == kaam); } }

代码重写了P对象的比较相等的逻辑,从而令p1和p2的比较结果返回为true。但同时需要重写hashCode的逻辑,否则返回值仍旧为false。

Dart 建议hashCode和Operator如有必要重写其中之一,那么另一个也需要重写,从而令哈希映射正常工作,否则Operator重写无效。

runtimeType

runtimeType是 read-only 属性,表达数据结构在运行时的类型。runtimeType涉及 Dart VM 运行机制,此处留坑以后再来填。

noSuchMethod

当调用对象上不存在的方法时,就会触发noSuchMethod,考察如下代码:

void main() { P p = P(); print(p.add(888)); } class P { @override noSuchMethod(Invocation invocation) => 'Got the ${invocation.memberName} with arguments ${invocation.positionalArguments}'; }

在 DartPad 编辑器运行上述代码,发现并未触发noSuchMethod方法, 而是直接抛出了编译错误。这是因为noSuchMethod触发需要有两个条件:

调用方必须是dynamic类型; 调用方具有被调用方法的定义但未实现,同时noSuchMethod也被重写;

所以只有如下两种情况,才会触发noSuchMethod:

void main() { dynamic p = P(); Q q = Q(); // 该情况下,q 可以是 Q 类型,也可以是 dynamic print(p.add(123)); print(q.add(123)); } class P { @override noSuchMethod(Invocation invocation) => 'Got the ${invocation.memberName} with arguments ${invocation.positionalArguments}'; } class Q { miss(int data); @override noSuchMethod(Invocation invocation) => 'Got the ${invocation.memberName} with arguments ${invocation.positionalArguments}'; } toString

toString方法使用字符串来表达对象的信息,也可以在将数字转换为字符串的场景下使用。开发者也可以重写 toString方法,以加入自定义内容。

void main() { P p = P(); p.toString(); } class P { @override toString() { return 'this is custom text' } } 二、Dart 类与基本方法 1.类的定义和构造函数 class P { String name; int age; P(String dataName, int dataAge) { name = dataName; age = dataAge; } bool isOld() { return age > 30 ? true : false; } } void main() { var p = new P('tom', 12); print(p.name); }

上述代码中,声明了P类,P 中含有两个属性:name和age。同时也声明了构造函数,通过向构造函数传入参数从而创建实例p。

创建实例仍然使用传统的new方法,但在 Dart 2 以上版本,new关键字可以省略,同时构造函数也可以用语法糖简化,代码写法如下:

class P { String name; int age; P(this.name, this.age); bool isOld() { return age > 30 ? true : false; } } void main() { var p = P('tom', 12); print(p.name); // tom } 命名构造函数

除默认的构造函数外,Dart 提供命名构造函数方法。代码如下:

class P { String name; int age; P(this.name, this.age); P.init(String dataName, int dataAge) { name = dataName; age = dataAge; } bool isOld() { return age > 30 ? true : false; } } void main() { var p = P.init('tom', 12); print(p.name); // tom }

命名构造函数的功能看起来与默认构造函数的功能类似,那设计该机制的目的是什么呢?原因是 Dart 不支持构造函数的重载,无法使用不同的参数来执行构造方法,所以提供命名构造函数的机制来实现多方式创建实例。

工厂构造函数

除了上述两种构造函数外,Dart 还提供第三种构造函数:工厂构造函数。它的使用场景是:如果调用构造函数时,如果实例已存在,不会重新创建实例,而是使用已存在的实例,保证环境内只有一个实例存在,也就是单例模式。考察如下代码:

class P { String name; static Map _cache = {}; factory P(String name) { if (_cache.containsKey(name)) { return _cache[name]; } else { final p = P._internal(name); _cache[name] = p; return p; } } P._internal(this.name); } void main() { final p = P('tom'); print(p.name); }

工厂构造函数不允许访问this,所以_cache的形态必须是static。每次创建实例时,如果实例已经在_cache中存在,那么返回已存在的实例。换句话说,工厂构造函数并没有自动创建实例,而是把决定权交给开发者。

2.类的属性和方法 静态变量和静态方法

和大多数语言一样,Dart 提供静态变量和静态方法:

class P { static age; static bool isOld() { return age > 30 ? true : false; } }

静态方法无法使用this,也不能访问非静态成员,类的实例也无法调用静态方法,并且静态变量只有在被使用的时候才会初始化。

私有属性和私有方法

Dart 不提供类似public、protected等关键字,在变量前添加下划线即可声明私有:

class P { int _age; P(this._age); bool _isOld() { return this._age > 30 ? true : false; } bool isOld() { return _isOld(); } } void main() { final p = P(20); print(p._age); // error print(p._isOld()); // error print(p.isOld()); // false }

实例无法直接调用私有方法,但是可以通过调用公有方法的形式间接调用私有方法。

3.类的继承 构造函数

Dart 通过extends关键字实现继承,子类继承父类中公有的属性和方法,不会继承构造函数,所以子类的构造函数需通过super关键字来调用或改造父类的构造函数:

class P { num name; num age; P(this.name, this.age); P.xxx(this.name, this.age); } // class Q extends P { // Q(num name, num age): super(name, age); // } // class Q extends P { // num sex; // Q(num sex, num name, num age): super.xxx(name, age) { // this.sex = sex; // } // } class Q extends P { num sex; Q(num sex, num name, num age): super(name, age) { this.sex = sex; } } void main() { final q = Q(12, 13, 14); print(q.sex); // 12 }

上述代码演示了子类中三种构造函数的表现:

直接复用父类构造函数 复用和改造父类默认构造函数 复用和改造父类命名构造函数 子类调用父类方法

如果子类需要调用父类方法,同样使用super关键字,此时方法内部的this指向子类:

class P { num name; num age; P(this.name, this.age); bool childCheck() { return age > 20 ? true : false; } } class Q extends P { Q(num name, num age): super(name, age); bool check() { return super.check(); } } void main() { final a = Q(12, 13); print(a.childCheck()); // false } 子类重写父类方法 class P { num name; num age; P(this.name, this.age); bool check() { return age > 20 ? true : false; } } class Q extends P { Q(num name, num age): super(name, age); @override bool childCheck() { return age == 13 ? true : false; } } void main() { final a = Q(12, 13); print(a.childCheck()); // true }

子类在重写父类方法时,只要方法名称与父类相同,便可实现逻辑重写,@override为可选项,对于复杂逻辑的类功能建议添加@override。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有