百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Flutter—Dart类

toyiye 2024-06-21 11:56 14 浏览 0 评论

Dart是一种面向对象的语言,同时具有类和基于mixin的继承性。每个对象都是一个类的实例,除Null以外的所有类都继承自object。基于mixin的继承,意味着尽管每个类(除了顶级类Object?)只有一个超类,但类体可以在多个类层次中重用。

对象主要包含由函数和数据(方法和实例变量)组成的成员。如果要调用类方法或者成员变量,需要在一个对象基础上调用它。

扩展方法是在不改变类或创建子类的情况下向类添加功能的一种方法。

实例变量

下面是声明实例变量的方式:

class Point {
  double? x;  // 定义变量 x, 初始值 null.
  double? y;  // 定义变量 y, 初始值 null.
  double z = 0;  // 定义变量 z, 初始值 0.
}

所有未初始化的实例变量的值都是null。所有实例变量都会生成一个隐式的getter方法,非 final实例变量和late final实例变量也会生成隐式setter方法。

实例变量可以是final,但是只能被赋值一次。可以通过构造函数参数赋值或者构造函数列表初始化赋值,代码如下:

class ProfileMark {
  final String name;
  final DateTime start = DateTime.now();

 //构造函数赋值
  ProfileMark(this.name);
 //命名构造函数--列表初始化赋值
  ProfileMark.unnamed() : name = '';
}

如果需要在构造函数体启动后赋值给final实例变量,你可以使用以下方法之一:

  • 使用工厂构造函数
  • 使用late final,但是要注意late final 可能为空。

构造函数

通过创建与其类同名的函数来声明构造函数,最常见的构造函数形式是生成构造函数,创建一个类的新实例,如下:

class Point {
  double x = 0;
  double y = 0;

  Point(double x, double y) {
   // 初始化实例变量
    this.x = x;
    this.y = y;
  }
}

关键字this指的是当前实例。只有在名称冲突时才使用this,否则Dart可以会省略this关键字。

将构造函数参数赋值给实例变量的模式非常常见,因此Dart使用了初始化形式参数来简化这一过程。初始化参数还可以用于初始化不可空或final实例变量,这两者都必须初始化或提供默认值。简化代码如下:

class Point {
  final double x;
  final double y;

  Point(this.x, this.y);
}
  • 默认构造函数

如果不声明构造函数,则会为您提供默认构造函数。默认构造函数没有参数,并调用超类中的无参数构造函数

子类不从父类继承构造函数。没有声明构造函数的子类只有默认(无参数)构造函数

  • 命名构造函数

使用命名构造函数为一个类实现多个构造函数或提供额外的清晰度。

class Point {
  double x;
 double y;

  // Named constructor
  Point.origin(double x , double y){
  	this.x = x;
    this.y = y;
  }
}

//使用
Point point = new Point().origin(1.5, 2.5);
  • 调用超类非默认构造函数

超类的构造函数在构造函数体的开头被调用。如果还使用了初始化列表,则在父类被调用之前执行它。执行顺序如下:

  1. 初始化列表
  2. 父类的无参数构造函数
  3. 当前类的无参数构造函数

代码演示:

class Person {
  String? firstName;

  Person.from(String name): assert( name != null) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person 对象没有默认构造方法;
  // 子对象必须调用super.fromJson().
  Employee.from(super.data) : super.from() {
    print('in Employee');
  }
}

void main() {
  var employee = Employee.from("Lucy");
  print(employee);
  // Prints:
  // in Person
  // in Employee
  // Instance of 'Employee'
}

以上演示了代码执行过程,执行顺序为:

  1. assert( name != null)
  2. Person.from
  3. Employee.from

为了避免必须手动将每个参数传递到构造函数中调用,可以使用超类初始化式参数将参数转发到指定的或默认的超类构造函数。如下:

class Vector2d {
  final double x;
  final double y;

  Vector2d(this.x, this.y);
}

class Vector3d extends Vector2d {
  final double z;

  //等价于 Vector3d(final double x, final double y, this.z) : super(x, y);
  Vector3d(super.x, super.y, this.z);
}
  • 重定向构造函数

有时构造函数的唯一目的是重定向到同一类中的另一个构造函数。重定向构造函数的主体为空,构造函数调用(使用this而不是类名)出现在冒号(:)之后:

class Point {
  double x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // 委托给主构造函数
  Point.alongXAxis(double x) : this(x, 0);
}
  • 常量构造函数

如果类生成的对象永远不会更改,则可以将这些对象设置为编译时常量。为此,需要定义一个const构造函数,并确保所有实例变量都是final变量。

class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}
  • 工厂构造函数

如果希望不总是创建类的新实例的构造函数时,使用factory关键字。例如,工厂构造函数可能从缓存返回一个实例,也可能返回子类型的实例。

注意:工厂构造函数不能访问this

在下面的例子中,Logger工厂构造函数从缓存返回对象,而Logger. fromjson工厂构造函数从JSON对象初始化一个final变量:

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) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

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

调用工厂构造函数和其他构造函数一样:

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

var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);

方法

方法是为对象提供行为的函数。

  • 实例方法

对象上的实例方法可以访问实例变量。下面的例子中的distanceTo()方法是一个实例方法的例子:

import 'dart:math';

class Point {
  final double x;
  final double y;

  Point(this.x, this.y);

  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}
  • 操作符方法

操作符是具有特殊名称的实例方法。Dart允许使用以下名称定义操作符:

<

+

|

>>>

>

/

^

[]

<=

~/

&

[]=

>=

*

<<

~

-

%

>>

==

以下代码演示了 + 和 - 操作符:

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}
  • getter和setter方法

getter和setter是提供对对象属性的读写访问的特殊方法。每个实例变量都有一个隐式的getter,如果合适的话还会加上一个setter。可以通过使用get和set关键字实现getter和setter来创建其他属性。代码演示如下:

class Rectangle {
  double left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // 如下定义了两个计算属性: right  bottom.
  double get right => left + width;
  set right(double value) => left = value - width;
  double get bottom => top + height;
  set bottom(double value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}
  • 抽象方法

Instance、getter和setter方法可以是抽象的,定义一个接口,但将其实现留给其他类。抽象方法只能存在于抽象类中。

abstract class Doer {
   void doSomething();  // 定义抽象方法
}

class EffectiveDoer extends Doer {
  void doSomething() {
    //Todo
  }
}

抽象类

使用abstract修饰符来定义一个抽象类——不能实例化的类。抽象类在定义接口时很有用,通常还带有一些实现。如果希望抽象类看起来是可实例化的,请定义一个工厂构造函数。

抽象类通常有抽象方法。下面是一个声明具有抽象方法的抽象类的例子:

abstract class AbstractContainer {
  // Define constructors, fields, methods...

  void updateChildren(); // 抽象方法.
}

类继承

使用extends创建子类,使用super引用父类:

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}
  • 方法重写

子类可以重写实例方法(包括操作符)、getter和setter。使用@override注释来表示重写一个成员:

class Television {
  // ···
  set contrast(int value) {...}
}

class SmartTelevision extends Television {
  @override
  set contrast(num value) {...}
  // ···
}

重写的方法声明必须在以下几个方面与它覆盖的方法(或方法)匹配:

  • 返回类型必须与被重写方法的返回类型(或其子类型)相同。
  • 参数类型必须与被重写方法的参数类型相同(或其超类型)。
  • 如果被重写的方法接受n个位置参数,那么重写的方法也必须接受n个位置参数。
  • 泛型方法不能覆盖非泛型方法,非泛型方法也不能覆盖泛型方法。

拓展方法

扩展方法是向现有库添加功能的一种方法。

下面是一个在string_apis.dart中定义的名为parseInt()的字符串上使用扩展方法的示例:

import 'string_apis.dart';
...
print('42'.padLeft(5));
print('42'.parseInt()); 

后面会专门使用一个章节介绍拓展方法。

枚举类型

枚举类型,通常称为枚举或枚举,是一种特殊的类,用于表示固定数量的常量值。

所有枚举自动扩展Enum类。它们也是密封的(sealed),这意味着它们不能子类化、实现、混合或以其他方式显式实例化。

enum Color { red, green, blue }

下面是一个示例,它声明了一个增强的枚举,其中包含多个实例、实例变量、getter和实现的接口:

enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round();

  @override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}

使用枚举:

final favoriteColor = Color.blue;
if (favoriteColor == Color.blue) {
  print('Your favorite color is blue!');
}

//获取枚举的index
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

//switch case
var aColor = Color.blue;
switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // Without this, you see a WARNING.
    print(aColor); // 'Color.blue'
}

向类中添加特性:mixins

Mixins是在多个类层次结构中重用类代码的一种方式。

要使用mixin,使用with关键字后跟一个或多个mixin名称。下面的例子展示了两个使用mixin的类:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

要实现mixin,创建一个继承Object且不声明构造函数的类。除非你想让你的mixin作为常规类使用,否则使用mixin关键字来代替class。例如

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

如果想要限制可以使用mixin的类型。例如,mixin可能依赖于能够调用mixin没有定义的方法。如下面的例子所示,你可以通过使用on关键字来指定所需的超类来限制mixin的使用:

class Musician {
  // ...
}
mixin MusicalPerformer on Musician {
  // ...
}
class SingerDancer extends Musician with MusicalPerformer {
  // ...
}

在前面的代码中,只有扩展或实现了Musician类才能使用mixin MusicalPerformer。因为SingerDancer扩展了SingerDancer,SingerDancer可以混合在MusicalPerformer中。

类变量和方法

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

  • 静态变量
class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

静态变量在使用之前不会初始化。

  • 静态方法

静态方法(类方法)不操作实例,因此不能访问实例。但是它们可以访问静态变量。如下面的示例所示,可以直接在类上调用静态方法。

import 'dart:math';

class Point {
  double x, y;
  Point(this.x, this.y);

  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

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

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码