一,概述

  (Class)是面向对象程序设计,实现信息封装的基础。类是一种用户定义的类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。

Dart的类与其它语言都有很大的区别,比如在dart的类中可以有无数个构造函数,可以重写类中的操作符,有默认的构造函数,由于dart没有接口,所以dart的类也是接口,因此你可以将类作为接口来重新实现。

  Dart是一门使用类和单继承的面向对象语言所有的对象都是类的实例,并且所有的类都是Object的子类。

二,类定义

  • 类的定义用class关键字
  • 如果未显式定义构造函数,会默认一个空的构造函数
  • 类首字母必须大写

  • 使用new关键字和构造函数来创建对象
  • class  Person { //未定义父类的时候,默认继承自Object
    num x;
    num y;
    num z;
    } void main(List<String> args){
    var person = new Person();//调用默认的构造函数
    person.x = ; //使用点(.)引用实例变量或方法
    person.y = ;
    person?.z = ; //如果p不为空,设置它的变量y的值为4
    print(person.x);
    print(person.y);
    print(person.z);
    }

    结果:

    
    

三, 实例变量

  • 声明实例变量时,所有未初始化的实例变量的值为null
  • 对象的成员包括函数和数据(分别是方法和实例变量)。使用点(.)引用实例变量或方法;
  • 使用?.来确认前操作数不为空, 常用来替代. , 避免左边操作数为null引发异常
  • void main(){
    var point = new Point();
    point.x = ; //使用点(.)引用实例变量或方法
    point?.y = 5;//如果p不为空,设置它的变量y的值为5
    print(point.x); print(point.y);
    }
    class Point { 
    int x; // null
    int y; // null
    int z = ; //
    }

四,构造函数

  • 如果你没有声明构造函数,默认有构造函数,默认构造函数没有参数,调用父类的无参构造函数。子类不能继承父类的构造函数

    class Person {
    int x;
    int y;
    } void main(List<String> args){
    var person = new Person();
    }
  • 构造函数就是一个与类同名的函数,关键字 this 是指当前的,只有在命名冲突时有效,否则dart会忽略处理
  • void main(){
    var point = new Point(, );
    }
    class Point {
    int x;
    int y;
     //自己定义的类名构造函数
      Point(int x, int y) {
    this.x = x;
       this.y = y;
    }
    }
  • 在Dart中构造函数的名称可以是类名 ClassName  或者类名和标识符 ClassName.identifier 。 其中构造函数名称是“ClassName”的函数叫“类名构造函数”;构造函数名称是“ClassName.identifier”的函数叫“命名构造函数”。

    (1)类名构造函数 (ClassName)

    import 'dart:math';
    
    class Point {
    int y;
    int x; // 类名构造函数
    Point(num x, num y) {
    this.x = x;
    this.y = y;
    }
    // .....
    }

    在构造函数里初始化成员属性是很常见的事情,因此Dart开发了新的语法糖来简化这种操作,比如将Point的类名构造构造函数改写成

    class Point {
    num x, y;
    // 注意x,y的赋值会在构造函数执行之前完成.
    Point(this.x, this.y);
    }

    (2)命名构造函数(ClassName.identifie) 
      使用命名构造函数可以为类提供多个构造函数,按官方的说法就是提供额外的清晰度

    class Point {
    num x, y; Point(this.x, this.y); // 命名构造函数
    Point.origin() {
    x = ;
    y = ;
    }
    }

      调用命名构造函数

    main(List<String> args) {
    // 调用命名构造函数
    Point point1 = Point.origin();
    }

 在命名构造函数里也可以用新的语法糖来简化这种操作,比如将Point的类名构造构造函数改写成

  • class Point {
      num x, y;

    // 注意x,y的赋值会在构造函数执行之前完成.
      Point(this.x, this.y);
    }

  • (2)命名构造函数(ClassName.identifie)

      使用命名构造函数可以为类提供多个构造函数,按官方的说法就是提供额外的清晰度

    class Point {
    num x, y; Point(this.x, this.y); // 命名构造函数
    Point.origin() {
    x = ;
    y = ;
    }
    }

      调用命名构造函数

    main(List<String> args) {
    // 调用命名构造函数
    Point point1 = Point.origin();
    }

      在命名构造函数里也可以用新的语法糖来简化这种操作,比如将Point的类名构造构造函数改写成

    class Point {
      num x, y;
      //类名构造函数
    Point(this.x, this.y);
    // 命名构造函数
    Point.origin(this.x,this.y);
    }
    void main(List<String> args){
    var point = new Point.Orgin(,);
    print(point.x);
    print(point.y);
    }

    (3)默认构造函数(前面我我们已经说了,我们放在这里再提一下,方便区分)
       如果类中没有声明构造函数,Dart会提供一个默认的构造函数。这个默认的构造函数会调用父类的默认构造函数,并且该构造函数是没有参数的。

    class Person {
    int x;
    int y;
    } void main(List<String> args){
    var person = new Person();
    }
  • Dart的第一个版本实例化对象需要new关键字,但在Dart 2之后就去掉了new关键字

    main(List<String> args) {
    // 调用类名构造函数
    Point point1 = Point(,);
    print(point1.x);
    }
  • 调用父类非默认的构造函数(类比下面的重定向理解记忆)

    在默认情况下,子类可以调用父类的未命名,无参数的构造函数即默认构造函数。父类的构造函数会在子类的构造函数之前开始调用,如果子类中存在需要初始化的成员属性,则可以先初始化子类成员属性,再调用父类的构造函数,执行过程如下

    1. 初始化子类成员属性
    2. 调用父类构造函数
    3. 子类构造函数

    如果父类中没有默认的构造函数,你必须手动调用父类的构造函数,在子类的构造函数体之前通过 : 指定调用父类构造函数,示例如下

    // Person类中没有一个无参数,未命名的构造函数
    class Person {
    String firstName;
    // 命名构造函数
    Person.fromJson(Map data) {
    print('in Person');
    }
    } class Employee extends Person {
    // 你必须调用父类的super.fromJson(data).
    Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
    }
    } main() {
    var emp = new Employee.fromJson({});
    }
  • 重定向构造函数 (在这里 :有重新指向的含义)

    有时构造函数的唯一目的是重定向到同一类中的另一个构造函数重定向构造函数的主体为空构造函数调用出现在冒号( :)之后 。 大意就是在创建类时,我定义一个命名构造函数,但是这个构造函式的主体我不实现。直接通过:另外一个构造函数。实现对外界传入的参数接收并赋值给内部的变量。

    class Point {
    num x, y;
    //类名构造函数
    Point(this.x, this.y);
    // 命名构造函数
     Point.order(this.x,this.y);
     Point.origin(num a,num b):this.order(a,b); //重定向构造函数, origin构造函数将外界的传值,指向给了order构造函数。
    }
    void main(List<String> args){
    var point = new Point.origin(,);
    print(point.x);
    print(point.y);
    }
  • 常量构造函数 
    如果你的类创建的对象从不改变,你可以创建一些编译时的常量对象。因此,定义一个const构造函数,且保证所有的对象变量都是final。
    class ImmutablePoint {
    static final ImmutablePoint origin = const ImmutablePoint(, );
    final num x, y;
    const ImmutablePoint(this.x, this.y);
    }
  • 工厂构造函数

    在实现一个构造函数时使用factory关键字,该构造函数并不总是创建其类的新实例。例如,工厂构造函数可能会从缓存中返回实例,也可能会返回子类型的实例。

    class Logger {
    final String name;
    bool mute = false; // _cache是私有变量
    //_在名称前,表示该变量为私有
    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);
    }
    }
    注意:工厂构造者对this没有访问权限。

    像调用任何其他构造函数一样调用工厂构造函数:

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

五,方法

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

  • Getters和Setters 方法
     (1)Getters和setters是读取和修改对象的特定方法,每次调用对象的属性时,Dart都会隐式的调用一次getter方法,这允许你可以在修改或者读取对象属时做一些操作。
     (2)通过 get和 set 关键词重写对象的默认行为。

    class Rectangle {
    num left, top, width, height;
    //类名构造函数
    Rectangle(this.left, this.top, this.width, this.height);
    // 重写right属性(类比oc记忆,这里多了一个set和get的关键字)
    num get right => left + width;
    set right(num value) => left = value - width;
    num get bottom => top + height;
    set bottom(num value) => top = value - height;
    } void main() {
    var rect = Rectangle(, , , );
    assert(rect.left == );
    rect.right = ;
    assert(rect.left == -);
    }
  • 实例方法
    在对象的实例方法有权限获取对象变量和this,在接下来的例子里distanceTo就是一个对象方法:

    import 'dart:math';
    class Point {
    num x, y;
    Point(this.x, this.y);
    num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
    }
    }
  • 抽象方法

    (1) 实例的getter和setter方法就是抽象的方法,定义一个接口,但将其实现留给其他类。
    (2)抽象方法使用分号 ; 而不是方法体
    (3)抽象方法只存在于抽象类中。

    abstract class Doer {
    //...定义实例变量和方法... //定义一个抽象方法
    void doSomething();
    } class EffectiveDoer extends Doer {
      void doSomething() {
    //...实现一个抽象方法...
    }
    }

六,抽象类和接口

  • 抽象类
    使用 abstract 修改器可以定义一个抽象类。抽象类是不能被实例化的,但对于定义接口是非常有用的,如果你想实例化抽象类,你必须实现抽象类,才能被实例化

  • // 此对象爱你过是抽象类,因此不能被实例化
    abstract class AbstractContainer {
    // 定义构造函数、字段、方法... void updateChildren(); // 抽象方法
    }
  • 隐式的接口
    每个类都是都是隐式的接口,包括类的方法和属性。如果你想创建一个类A不继承B的实现,可以实现B的接口来创建类A。一个类允许通过implements 关键词可以实现多个接口

    // 每个类都是一个隐式的接口,所以Person类也是个接口,包括成员属性和方法.
    class Person {
    // 可在接口中实现, 但仅对这个库可见.
    final _name; // 构造函数不能够被接口实现
    Person(this._name); // 可在接口中实现.
    String greet(String who) => 'Hello, $who. I am $_name.';
    } // 实现Person接口.
    class Impostor implements Person {
    get _name => ''; String greet(String who) => 'Hi $who. Do you know who I am?';
    } String greetBob(Person person) => person.greet('Bob'); void main() {
    print(greetBob(Person('Kathy')));
    print(greetBob(Impostor()));
    }

    实现多个接口

    class Point implements Comparable, Location {...}

七,类的继承

  • 使用extends创建子类,super引用父类,子类可以重写实例方法、getter和setter,使用@override注释重写,使用@proxy注释来忽略警告

    class Television {
    void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
    }
    } class SmartTelevision extends Television {
    void turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
    }
  • 重写成员

    可以使用 @override 关键字,子类可以重写实例的方法,getters和setters

    class SmartTelevision extends Television {
    @override
    void turnOn() {...}
    // ···
    }
  • 重写操作符

    你可以重写以下表中显示的运算符。例如,如果定义Vecor类,则可以定义+方法来添加两个vectors。
    注意:
      你可能已经注意到了!=不是可重写的运算符。表达式E1!= E2只是语法上的糖!( E1 = = E2 )

    <    +    |    []
    > / ^ []=
    <= ~/ & ~
    >= * << ==
    – %
  • 可以重写操作符,下面是重写加减操作符的示例

    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); // Operator == and hashCode not shown. For details, see note below.
    // ···
    } void main() {
    final v = Vector(, );
    final w = Vector(, ); assert(v + w == Vector(, ));
    assert(v - w == Vector(, ));
    }

    如果你需要重写 == 操作符,请参考操作符教程

  • noSuchMethod()
    当用户调用你定义的类中不存在的属性与方法时,可以做出一些响应,通过重写noSuchMethod()

    class A {
    @override
    void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
    '${invocation.memberName}');
    }
    }

八,类变量和类方法  

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

  • 静态变量
    静态变量(类变量)对于类范围的状态和常量非常有用:
    静态变量在使用之前不会初始化。

    class Queue {
    static const initialCapacity = ;
    // ···
    } void main() {
    assert(Queue.initialCapacity == );
    }
  • 静态方法

    静态方法(类方法)不能在实例操作,因此它没有访问this的权限。

    import 'dart:math';
    
    class Point {
    num x, y;
    Point(this.x, this.y);
    static num 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(, );
    var b = Point(, );
    var distance = Point.distanceBetween(a, b);
    assert(2.8 < distance && distance < 2.9);
    print(distance);
    }

    注意:
     (1)为了常用或广泛使用的实用程序和功能,考虑使用顶层函数,而不是静态方法。

    import 'dart:math';
    
    class Point {
    num x, y;
    Point(this.x, this.y);
    }
    // 顶级函数
    num 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(, );
    var b = Point(, );
    var distance = distanceBetween(a, b);
    assert(2.8 < distance && distance < 2.9);
    print(distance);
    }

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

九,访问控制

  • 默认类中的所有属性和方法是public的。在dart中,可以在属性和方法名前添加“_”使私有化。现在让我们使name属性私有化。

    main(List<String> args) {
    Dog d = new Dog('Duffy', );
    print(d.name); //This will throw error
    } class Dog {
    String _name; //私有的变量
    int age; //公有变量
     //类名构造函数
    Dog(this.name, this.age);
     //setter && getter 方法
    String get respectedName {
    return 'Mr.$name';
    }
    set respectedName(String newName) {
    name = newName;
    }
     //命名构造函数
    Dog.newBorn() {
    name = 'Doggy';
    age = ;
    }
     //公有实例方法
    bark() {
    print('Bow Wow');
    }
     //私有的实例方法
    _hiddenMethod() {
    print('I can only be called internally!');
    }
    }

十,枚举类型

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

  • 使用枚举
    使用enum关键词来声明一个枚举类型

    enum Color { red, green, blue }

    枚举中的每个值都有一个index索引,它返回枚举声明中值的从零开始的位置。例如,第一个值具有索引0,第二个值具有索引1。

    assert(Color.red.index == );
    assert(Color.green.index == );
    assert(Color.blue.index == );

    若要获取枚举中所有值的列表,请使用枚举的values常量。

    List<Color> colors = Color.values;
    assert(colors[] == Color.blue);

    你可以在switch语句中使用枚举,如果不处理枚举的所有值,将会收到警告:

    var aColor = Color.blue;
    
    switch (aColor) {
    case Color.red:
    print('Red as roses!');
    break;
    case Color.green:
    print('Green as grass!');
    break;
    default: // 没有default,将会报错
    print(aColor); // 'Color.blue'
    }

    枚举类型有以下限制:

    • 你不能子类化、混合或实现枚举。
    • 不能显式实例化枚举。

十一,泛型

  • 泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。
  • 从字面的意思理解来看,泛型,泛就是模糊、暂不确定暂定的意思。可以这样理解,使用泛型就是,定义的一个类型,类型暂不确定,给使用给一个占位符给代替,在使用的时候可以给确定其定义的类型。
  • 泛型,基本上强类型语言都支持泛型,比如java,Oc,swift 所以Dart也不例外
  • dart全面支持泛型。假设你想在你定义的类中,想持有任意类型的数据。如下是怎样使用泛型定义这样的类。
    main(List<String> args) {
    DataHolder<String> dataHolder = new DataHolder('Some data');
    print(dataHolder.getData());
    dataHolder.setData('New Data');
    print(dataHolder.getData());
    } class DataHolder<T> {
    T data; DataHolder(this.data); getData() {
    return data;
    } setData(data) {
    this.data = data;
    }

【dart学习】-- Dart之类和对象的更多相关文章

  1. [dart学习]第四篇:函数和操作符(本篇未完待续)

    接着学习dart的函数和操作符. 1.函数Function dart是一种真正的面向对象的语言,通常一个函数也是Function类型的对象,这也就是说可以把函数赋值给一个变量,或者作为另一个函数的入参 ...

  2. [dart学习]第二篇:dart变量介绍 (一)

    前言 本文的所有内容均是官方文档的简单翻译和理解,需要查看原文,请登录  https://www.dartlang.org/guides/language/language-tour  阅读, 让我们 ...

  3. 【dart学习】-- Dart之异步编程

    一,概述 编程中的代码执行,通常分为同步与异步两种. 同步:简单说,同步就是按照代码的编写顺序,从上到下依次执行,这也是最简单的我们最常接触的一种形式.但是同步代码的缺点也显而易见,如果其中某一行或几 ...

  4. 【dart学习】-- Dart之函数

    1. 指定返回值得函数 /** * 无返回值的函数 * params: 可以是任意类型(var和Object类型也可以任意类型). 当然这里的参数类型你可以随意指定我这里已dynamic为例 * 参数 ...

  5. Dart语言学习( 一) 为什么学习Dart?

    为什么学习Dart? Google及全球的其他开发者,使用 Dart 开发了一系列高质量. 关键的 iOS.Android 和 web 应用. Dart 非常适合移动和 web 应用的开发. 高效 D ...

  6. Dart 学习资料

    Dart 学习资料: 学习资料 网址 Dart 编程语言中文网 http://dart.goodev.org/ Dart 官方包仓库 https://pub.dartlang.org/ 你想了解的Da ...

  7. [dart学习]第五篇:操作符

    前言:本系列内容假设读者有一定的编程基础,如了解C语言.python等. 本节一起来学习dart的操作符,直接拷贝官网的操作符描述表如下: Description Operator unary pos ...

  8. Dart学习笔记-运算符-条件表达式-类型转换

    Dart学习笔记-运算符-条件表达式-类型转换 一.运算符 1.算术运算符 + (加)- (减)* (乘)/ (除)~/ (取整) %(取余) 2.关系运算符 == (等等) != (不等) > ...

  9. Dart 学习

    语言特性 Dart所有的东西都是对象, 即使是数字numbers.函数function.null也都是对象,所有的对象都继承自Object类. Dart动态类型语言, 尽量给变量定义一个类型,会更安全 ...

  10. 简单易懂的Dart》 - Dart语言中文简明教程

    转自:https://www.blackglory.me/straightforward-dart/ Dart是Google公司发布的网络编程语言,其诞生的目的是为了让广大C类OOP程序员们克服Jav ...

随机推荐

  1. C# GDI+简单绘图

    一.使用Pen画笔 Pen的主要属性有: Color(颜色),DashCap(短划线终点形状),DashStyle(虚线样式),EndCap(线尾形状), StartCap(线头形状),Width(粗 ...

  2. 【Flutter学习】可滚动组件之ScrollView

    一,概述 ScrollView 是一个带有滚动的视图组件. 二,组成部分 ScrollView 由三部分组成: Scrollable - 它监听各种用户手势并实现滚动的交互设计.可滚动Widget都直 ...

  3. sql server 基础语法4 实践练习+子查询

    drop table class create table class ( classId ) primary key not null, cName ) ) insert into class ', ...

  4. 探索Redis设计与实现7:Redis内部数据结构详解——intset

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  5. webpack+vue+koa+mongoDB,从零开始搭建一个网站

    github 地址 https://github.com/wangxiaoxi... webpakc+vue的搭建1.新建项目文件夹(see-films);2.npm init //初始化项目3.搭建 ...

  6. CSS入门之盒模型(六分之四)

    盒模型要点知识 务必注意看,这可是前端面试 必定会遇到 的问题. box-sizing 盒模型的主要CSS属性,除继承外有两个值: content-box 这里不再细说历史原因,只说其作用. cont ...

  7. 32. 持续集成简介及JDK、Tomcat、Jenkins环境搭建

    持续集成简介 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成.每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验 ...

  8. PAT_A1100#Mars Numbers

    Source: PAT A1100 Mars Numbers (20 分) Description: People on Mars count their numbers with base 13: ...

  9. log4j日志记录到文件

    要写日志信息到一个文件中,必须使用org.apache.log4j.FileAppender.有以下FileAppender的配置参数: FileAppender配置: 属性 描述 immediate ...

  10. 8种常见SQL错误用法,你中招了吗?

    作者:db匠 来源:https://yq.aliyun.com/articles/72501 1.LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如对于下面简单的语句, ...