news 2026/8/25 17:33:13

Android学Dart学习笔记第十五节 类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android学Dart学习笔记第十五节 类

文档描述

Dart is an object-oriented language with classes and mixin-based inheritance. Every object is an instance of a class, and all classes except Null descend from Object. Mixin-based inheritance means that although every class (except for the top class, Object?) has exactly one superclass, a class body can be reused in multiple class hierarchies. Extension methods are a way to add functionality to a class without changing the class or creating a subclass. Class modifiers allow you to control how libraries can subtype a class.

Dart是一种基于类和mixin的继承的面向对象语言。每个对象都是某个类的实例,而除Null之外的所有类都是object的后代
基于mixin的继承意味着尽管每个类(除了最上面的类,Object?)都只有一个超类,但一个类的主体可以在多个类层次中重用。
扩展方法是一种向类添加功能而不改变类或创建子类的方法。
类修饰符允许你控制库如何为一个类添加子类型。

信息量极大,暂时不理解没关系,继续看

Using class members 使用类成员

这部分和kt一样
使用点(.)来引用实例变量或方法:

varp=Point(2,2);// Get the value of y.assert(p.y==2);// Invoke distanceTo() on p.double distance=p.distanceTo(Point(4,4));

使用?.而不是.为了避免最左边的操作数为null时发生异常:

// If p is non-null, set a variable equal to its y value.vara=p?.y;

Using constructors

You can create an object using a constructor. Constructor names can be either ClassName or ClassName.identifier.

这点和java略有不同。 在下面例子中的三个函数都是构造函数。ClassName.identifier形式的构造函数,又叫命名构造函数,所有formJson是命名工厂构造函数

classPoint{varx;vary;// 1. 生成构造函数(Generative Constructor)// 最常见的构造函数,直接创建新实例Point(this.x,this.y);// 2. 命名构造函数(Named Constructor)// 只是语法糖,仍然是生成构造函数Point.origin():x=0,y=0;// 3. 工厂构造函数(Factory Constructor)// 不总是创建新实例,可以返回缓存实例或子类实例factoryPoint.fromJson(Map<String,int>json){returnPoint(json['x']!,json['y']!);}}

在dart中,new关键字是可选的,两者等价。

finalp=newPoint(1,2);varnewP=Point(1,2);

有一些类提供了常量构造函数,如下:

classImmutablePoint{finaldouble x,y;constImmutablePoint(this.x,this.y);}

要使用常量构造函数创建编译时常量,请将const关键字放在构造函数名称之前,如下

varc=constImmutablePoint(1,2);varc1=constImmutablePoint(1,2);print(c==c1);//true

如果不需要也可以直接创建

varc=ImmutablePoint(1,2);varc1=ImmutablePoint(1,2);print(c==c1);//false

如果一个字段被定义为常量,后面的cosnt是可以省略的

constc=ImmutablePoint(1,2);constc1=ImmutablePoint(1,2);print(c==c1);//true

你可以仔细看看上面3段的区别
下面的官方的例子:

// Lots of const keywords here.constpointAndLine=const{'point':const[constImmutablePoint(0,0)],'line':const[constImmutablePoint(1,10),constImmutablePoint(-2,11)],};

省略后

// Only one const, which establishes the constant context.constpointAndLine={'point':[ImmutablePoint(0,0)],'line':[ImmutablePoint(1,10),ImmutablePoint(-2,11)],};

如果常量构造函数在常量上下文之外(就是不是用的const a,而是var )并且在没有const的情况下调用,它会创建一个非常量对象(并且也不是 var a = const A())

Getting an object’s type

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

constc=ImmutablePoint(1,2);print('The type of a is ${c.runtimeType}');//The type of a is ImmutablePoint

使用类型测试操作符(is, as, is!)而不是runtimeType来测试对象的类型。在正式环境中,obj is A 比ibj.runtimeType更稳定。

Instance variables

classPoint{double?x;// Declare instance variable x, initially null.double?y;// Declare y, initially null.double z=0;// Declare z, initially 0.}

声明为nullable类型的未初始化实例变量的值为null。非空实例变量必须在声明时初始化。

所有实例变量都会生成一个隐式getter方法。没有初始化器的非最终实例变量和后期最终实例变量也会生成一个隐式setter方法。
setter&gettter方法我们在函数那一章学习过,已经忘却的同学可以回顾下(函数)

classPoint{double?x;// Declare instance variable x, initially null.double?y;// Declare y, initially null.}voidmain(){varpoint=Point();point.x=4;// Use the setter method for x.assert(point.x==4);// Use the getter method for x.assert(point.y==null);// Values default to null.}

初始化一个声明的非晚期实例变量会在实例创建时设置其值,在构造函数及其初始化列表执行之前。因此,非late实例变量的初始化表达式(在=之后)无法访问this

double initialX=1.5;classPoint{// OK, can access declarations that do not depend on `this`:double?x=initialX;// ERROR, can't access `this` in non-`late` initializer:double?y=this.x;// OK, can access `this` in `late` initializer:late double?z=this.x;// OK, `this.x` and `this.y` are parameter declarations, not expressions:Point(this.x,this.y);}

late我们之前在学习变量时也学习过,忘却的同学点这里变量

实例变量可以是final,在这种情况下,它们必须只设置一次。在声明时初始化最终的、非晚期的实例变量,可以使用构造函数的参数,也可以使用构造函数的初始化列表:

classProfileMark{finalString name;finalDateTime start=DateTime.now();ProfileMark(this.name);ProfileMark.unnamed():name='';}

如果需要在构造函数体启动后给final实例变量赋值,可以使用下列选项之一:
使用工厂构造函数;
使用late final,但要小心:没有初始化方法的late final会给API添加一个setter。(更多细节点这个文档了解)

Implicit interfaces

每个类都隐式定义了一个接口,其中包含该类的所有实例成员及其实现的任何接口。如果您想创建一个支持类B的API而不继承B实现的类A,类A应该实现B接口。

类通过在implements子句中声明一个或多个接口,然后提供这些接口所需的api来实现这些接口。

// A person. The implicit interface contains greet().classPerson{// In the interface, but visible only in this library.finalString _name;// Not in the interface, since this is a constructor.Person(this._name);// In the interface.Stringgreet(String who)=>'Hello, $who. I am $_name.';}// An implementation of the Person interface.classImpostorimplementsPerson{Stringget_name=>'';Stringgreet(String who)=>'Hi $who. Do you know who I am?';}StringgreetBob(Person person)=>person.greet('Bob');voidmain(){print(greetBob(Person('Kathy')));print(greetBob(Impostor()));}

这里使我有点懵懵的,有点不太好接受。 我们努力吧。
正如文档所言,每个类都定义了一个隐藏了接口,我可以理解为class,也是一种接口,当当作接口使用时就只有结构是有效的,当作类对象使用时,方法的实现才有效果。

一个类同样可以实现多个接口

classPointimplementsComparable,Location{...}

类变量和方法

使用static关键字实现类范围的变量和方法。

Static variables 静态变量
classQueue{staticconstinitialCapacity=16;// ···}voidmain(){assert(Queue.initialCapacity==16);}

静态变量在使用之前不会初始化,java是类加载时初始化

Static methods
import'dart:math';classPoint{double x,y;Point(this.x,this.y);staticdoubledistanceBetween(Point a,Point b){vardx=a.x-b.x;vardy=a.y-b.y;returnsqrt(dx*dx+dy*dy);}}voidmain(){vara=Point(2,2);varb=Point(4,4);vardistance=Point.distanceBetween(a,b);assert(2.8<distance&&distance<2.9);print(distance);}

同样,因为初始化时机的不同,静态方法不可以调用实例变量或者实例方法。

** 考虑为常见或广泛使用的实用程序和功能使用顶级函数而不是静态方法。**

可以使用静态方法作为编译时常量。例如,可以将静态方法作为参数传递给常量构造函数。

classExample{finalint value;constExample(this.value);staticintstaticMethod()=>42;}voidmain(){// 传递静态方法作为常量构造函数的参数constinstance=Example(Example.staticMethod());print(instance.value);// 输出: 42}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 0:53:46

LPDDR6 JEDEC 原文解读学习—2.4 Data Packet Format(3)(~持续更新)

插播&#xff1a;2025年马上就结束啦&#xff0c;今天更新一篇&#xff0c;预计12/17号再更新一篇&#xff08;给自己立flag&#xff09;&#xff0c;然后2025年就休假咯~2026年继续努力码文章&#xff0c;如果有任何问题&#xff0c;欢迎大家评论区评论&#xff0c;交流。2.4.…

作者头像 李华
网站建设 2026/8/25 13:46:53

【PHP性能优化关键一步】:深入PHP 8.6内存泄漏监控与自动预警方案

第一章&#xff1a;PHP 8.6 内存泄漏检测概述在现代Web应用开发中&#xff0c;PHP 8.6 引入了多项性能优化与内存管理改进&#xff0c;但复杂的应用逻辑仍可能导致内存泄漏问题。内存泄漏会逐渐消耗系统资源&#xff0c;最终导致脚本执行失败或服务器响应变慢。因此&#xff0c…

作者头像 李华
网站建设 2026/8/24 10:13:03

PHP 8.6兼容性测试实战(资深架构师亲授迁移经验)

第一章&#xff1a;PHP 8.6兼容性测试概述随着 PHP 8.6 的发布临近&#xff0c;开发者社区对新版本的期待与关注持续升温。该版本预计将引入多项性能优化、语法增强以及底层引擎改进&#xff0c;因此在升级前进行全面的兼容性测试显得尤为关键。兼容性测试不仅确保现有项目能在…

作者头像 李华
网站建设 2026/8/25 1:21:26

从入门到精通:用R Shiny打造可交互的多维度数据仪表盘

第一章&#xff1a;R Shiny 的多模态图表交互控件在构建数据驱动的 Web 应用时&#xff0c;R Shiny 提供了强大的交互能力&#xff0c;尤其在多模态图表控件的集成方面表现突出。通过结合输入控件与动态渲染函数&#xff0c;开发者能够实现用户操作与可视化输出的实时联动。基础…

作者头像 李华
网站建设 2026/8/24 17:28:05

光伏阵列遇到局部阴影就像吃火锅被隔壁桌抢肉——憋屈得很。今天咱们用Python整活,搞个3×3电池板的阴影仿真模型,重点观察串联结构在阴影下的输出曲线怎么抽风

3行3列的太阳能电池板局部遮阴仿真模型 可自己更改光照强度&#xff0c;十分方便 由于光伏电池的非线性受控电流源的特性&#xff0c;串联光伏阵列和并联光伏阵列在阴影条件下的输出特性是不同的。 当串联光伏阵列处于强阴影遮蔽时&#xff0c;即部分光伏电池辐照度严重降低时&…

作者头像 李华
网站建设 2026/8/25 10:39:56

你还不知道HTTP/3的这5个性能秘密?:资深架构师20年经验倾囊相授

第一章&#xff1a;HTTP/3 性能革命的底层逻辑HTTP/3 并非简单地对前代协议进行功能叠加&#xff0c;而是一次基于传输层重构的性能跃迁。其核心变革在于放弃沿用多年的 TCP 协议&#xff0c;转而采用基于 UDP 的 QUIC 协议作为传输基础。这一转变从根本上解决了队头阻塞问题—…

作者头像 李华