Dart --类

类概述

  • 普通类
    1. 变量
      • 实例变量(创建对象后,使用 对象.变量名 调用)
      • 静态变量(用static修饰,使用 类名.变量名 调用)
    2. 函数
      • 实例函数(创建对象后,使用 对象.函数名 调用)
      • 静态函数(用static修饰,使用 类名.函数名 调用)
    3. 构造函数
      • 默认构造函数
      • 自定义构造函数
      • 静态构造函数(使用const修饰的构造函数)
      • 重定向构造函数
      • 工厂构造函数
  • 抽象类
    1. 变量
      • 实例变量(其子类创建对象后,使用 对象.变量名 调用)
      • 静态变量(用static修饰,使用 类名.变量名 调用)
    2. 函数
      • 实例函数(其子类创建对象后,使用 对象.函数名 调用)
      • 静态函数(用static修饰,使用 类名.函数名 调用)
      • 抽象函数(其子类实现该函数,创建对象后,使用对象.函数名 调用)
    3. 不能实例化(工厂构造函数除外)。

Object

  • Object是所有类的父类。
  • Object没有父类。
  • 一个类只能有一个父类。
  • 如果一个类没有显示的用extends去继承一个类,那么默认其继承的是Object
  • Dart 是一种面向对象的语言,并且支持基于mixin的继承方式。
  • Dart 语言中所有的对象都是某一个类的实例,所有的类有同一个基类--Object。
  • 基于mixin的继承方式具体是指:一个类可以继承自多个父类。
  • 使用.来调用实例的变量或者方法。
  • 使用?.来确认前操作数不为空, 常用来替代. , 避免左边操作数为null引发异常。
  • 级联操作符 .. , 可以连续调用对象的一些列属性或函数。
  • 使用new语句来构造一个类,构造函数的名字可能是ClassName,也可以是ClassName.identifier, 例如:
  • 创建类的实例,使用new 或const,new对应的是普通的构造函数,const对应的是用const形式的构造函数。
  • 使用runtimeType属性,在运行中获取对象的类型。该方法将返回Type 类型的变量。
  • 在类定义中,所有没有初始化的变量都会被初始化为null。
  • 构造函数不能继承(Constructors aren’t inherited)
  • 构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类是实现这个构造函数。

构造函数(Constructors)

  • 没有返回值(factory构造方法有返回值)
  • 构造函数名与类名相同
  • 默认构造函数,如果类中没有显示声明构造函数,那么会默认有个构造函数,默认构造函数是与类同名且无参数无返回值的函数。
    class Class01{
      //变量
      int a; 
      String b;
    //未声明构造函数
    
    //所以这个类默认有个构造函数
    //Class01(){}
    }
    
  • 自定义构造函数
    class Class02{
      int a;
      String b;
      //自定义的一个构造函数,有两个参数
      Class02(int a,String c){
        this.a = a;//名字冲突时,可使用 this
        b = b;
      }
    }
    void main(){
      var c02 = new Class02(3,"abc");
      print(c02.a);
    }
    '''
    //如果构造函数中的参数都是给实例变量赋值的,那么上面这种情况还可以写成下面这种方式,简化了:
    class Class02{
      int a;
      String b;
      //自定义的一个构造函数,有两个参数
      Class02(this.a,this.b);
    }
    void main(){
      var c02 = new Class02(3,"abc");
      print(c02.a);
    }
    ''';
    
  • 命名构造函数,一种可以为类声明多个构造函数的方式。注意这里没有重载的概念,不能声明只是参数类型或数量不同的构造函数,使用命名构造函数实现。
    class Class03{
      int a;
      String b;
      Class03(int a,String b){
        this.a = a;
        this.b = b;
      }
      Class03.fun1(int a){
        this.a = a;
      }
      Class03.fun2(String b){
        this.b = b;
      }
    }
    void main(){
      var class03 = new Class03(3, "ccc");
      var class04 = new Class03.fun1(4);
      var class05 = new Class03.fun2("ddd");
    }
    
  • 静态构造函数
    • 类的对象不会改变
    • 类的变量不会改变,也就是常量了
    • 使用final修饰变量
    • 使用const 修饰构造方法
    • 创建实例时,使用const 而不是new
    class Class04{
      final int a;
      final String b;
      const Class04(this.a,this.b);
      void fun01(){
        print("aa");
      }
    }
    void main(){
        var class06 = const Class04(4, "ccc");
        class06.fun01();
        print(class06.a);
    }
    
  • 重定向构造函数,在类的构造函数中,有时我们只是需要调用到另一个构造函数。
    class Class05{
      int a;
      String b;
      Class05(int a,String b){
        this.a = a;
        this.b = b;
      }
      Class05.fun1(int a){
        this.a = a;
      }
      Class05.fun2(String b):this.fun1(33);//重定向到fun1
      Class05.fun3(String b):this(33,"ddddd");//重定向到构造函数
    }
    
  • 工厂构造函数
    • 工厂构造函数不能用this
    • 使用factory修饰构造函数
    • 构造函数内有返回值,类型是当前类或其子类,此返回值可以是用命名构 造函数创建的,也可以是缓存中的。
    • 使用new创建实例
    class Class06{
      int a;
      static Class06 instance ;  //这里创建了一个单例
    
      //这里的构造函数用factory修饰,使用new时,
      //不再是创建一个全新的实例了,而是通过函数体内return获取到实例
      factory Class06(int a){
        if(instance==null){
          instance = new Class06.fun1(a);
        }
        return instance;
      }
      Class06.fun1(this.a);//注意这里是实例化当前对象的构造方法
    }
    void main(){
        var class07 = new Class06(3);//使用new
        print(class07.a);
    }
    

抽象类

  • 使用abstract修饰类。
  • 可定义实例方法。
  • 可定义抽象方法,抽象方法没有函数体。
  • 抽象类不能实例化(工厂构造函数除外)。
  • 子类继承抽象类后,必须实现所有抽象方法,除非子类也是抽象类。
  • 只有抽象类能定义抽象方法。
    //定义抽象类
    abstract class Class09{
      void fun01();//定义抽象方法
    }
    //继承抽象类
    class Class10 extends Class09{
      @override
      void fun01() {//实现抽象方法
        print("aaa");
      }
    }
    void main(){
     var c10 = new Class10();
     c10.fun01();
    }
    
  • 抽象方法
    '''
     Instance , getter 和 setter 方法可以是抽象的,也就是定义一个接口,
     但是把实现交给其他的类。要创建一个抽象方法,使用分号(;)代替方法体;
    ''';
     abstract class Doer {
        // ...定义实例变量和方法...
        void doSomething(); // 定义一个抽象方法。
     }
    class EffectiveDoer extends Doer {
        void doSomething() {
         // ...提供一个实现,所以这里的方法不是抽象的...
         }
    }
    

setters 和 Getters

  • 是一种提供对方法属性读和写的特殊方法。每个实例变量都有一个隐式的 getter 方法,合适的话可能还会有 setter 方法。你可以通过实现 getters 和 setters 来创建附加属性,也就是直接使用 get 和 set 关键词:
    借助于 getter 和 setter ,你可以直接使用实例变量,并且在不改变客户代码的情况下把他们包装成方法。
  • 不论是否显式地定义了一个 getter,类似增量(++)的操作符,都能以预期的方式工作。为了避免产生任何向着不期望的方向的影响,操作符一旦调用 getter ,就会把他的值存在临时变量里。
class Rectangle {
   num left;
   num top;
   num width;
   num height;

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

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

main() {
   var rect = new Rectangle(3, 4, 20, 15);
   assert(rect.left == 3);
   rect.right = 12;
   assert(rect.left == -8);
}

静态变量和静态函数

  • 使用static修饰的变量为静态变量。
  • 使用static修饰的函数为静态函数。
  • 静态变量和函数,使用类名直接调用。
  • 实例变量和函数,使用类的对象调用。
  • 静态变量和函数,不能访问实例变量和函数。
  • 静态函数内,不能使用this。
  • 普通类和抽象类都可以定义静态变量和函数
  • 只有当静态变量被使用时才被初始化。
  • 你可以将静态方法作为编译时常量。例如,你可以把静态方法作为一个参数传递给静态构造函数。
class Class11{
  static int a = 3;//静态变量
  int b = 4;//实例变量

  //静态方法
  static void fun01(int c){
    print(c);
    //print(b);//这里报错,静态方法内不能使用实例变量
  }
  //实例方法
  void fun02(){
    print(b);
  }
}
void main(){
    var class11 = new Class11();
    //实例变量和函数
    print(class11.b);
    class11.fun02();
    //调用静态变量和函数
    Class11.fun01(44);
    print(Class11.a);
}

枚举类

  • 是一种用来代表一个固定数量的常量的特殊类。
  • 使用enum声明枚举。
  • 每个枚举值都有一个唯一值。
  • 枚举不能使用new实例化 。
  • 使用枚举值 枚举.枚举值。
  • 你不能在子类中混合或实现一个枚举。

'''声明一个枚举类型需要使用关键字 enum :''';
 enum Color {
    red,
    green,
    blue
 }

'''
在枚举中每个值都有一个 index getter 方法,它返回一个在枚举声明中从 0 开始的位置。
例如,第一个值索引值为 0 ,第二个值索引值为 1 。
''';
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

'''要得到枚举列表的所有值,可使用枚举的 values 常量。''';

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

'''
你可以在 switch 语句 中使用枚举。
如果 e 在 switch (e) 是显式类型的枚举,那么如果你不处理所有的枚举值将会弹出警告:
''';

  Color 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'
   }
 

继承

使用extends 关键字表示继承。
构造方法不能被继承。
使用@override重写函数。
如果继承的是抽象类,要实现所有抽象函数。

  • 继承抽象类

    //定义抽象类
    abstract class Parent{
      int a = 1;
      String b = "bb";
      void fun1();//定义抽象方法
      void fun2(int a,int c){
        this.a = a;
        print(c);
      }
    }
    class Child extends Parent{
      String b = "child b";//重写了父类的属性
      //实现了父类的抽象函数
      @override
      void fun1() {
        print(b);
      }
    
      //重写了父类的函数
      @override
      void fun2(int a, int c) {
        print(a+c);
      }
    }
    
    void main(){
        var child = new Child();
        child.fun1();// child b
        child.fun2(3, 4); //7
      }
    
  • 继承普通类

    • 子类至少定义一个构造函数调用父类的任一构造函数,使用:super。
    • 子类的每个构造函数都要继承父类的任一构造函数。
    • 子类可重写父类的函数。
class Fruit{
  String name;
  int nums;
  Fruit(this.name);//定义构造函数
  Fruit.num(this.name,this.nums);//定义命名构造函数
  Fruit.con(num){//定义命名构造函数
    nums = num*2;
  }
  void fun1(){
    print(name);
  }
  void fun2(){
    print(nums);
  }
}

class Apple extends Fruit{
  String name;
  int nums;
  int color;
  //至少需要定义一个构造函数调用父类的任一构造函数
  Apple(String name) : super(name);
  Apple.con1(this.color,this.name): super.num(name,3);
  Apple.con2() : super.con(3){
    color = 3;
  }
  //重写父类的fun2函数
  @override
  void fun2() {
    print(color);
    super.fun2();//调用父类的fun2方法
  }
  //子类自己的方法
  void fun3(){
    print(nums);
  }
}



//使用 extends 创建一个子类,同时 supper 将指向父类:
 class Television {
    void turnOn() {
       _illuminateDisplay();
        _activateIrSensor();
    }
    // ...
 }

 class SmartTelevision extends Television {
    
    void turnOn() {
       super.turnOn();
       _bootNetworkInterface();
       _initializeMemory();
       _upgradeApps();
    }
    // ...
 }
  • 下面是个关于重写 Object 类的方法 noSuchMethod() 的例子,当代码企图用不存在的方法或实例变量时,这个方法会被调用。
  class A {
    // 如果你不重写 noSuchMethod 方法, 就用一个不存在的成员,会导致NoSuchMethodError 错误。
    void noSuchMethod(Invocation mirror) {
        print('You tried to use a non-existent member:' + 
            '${mirror.memberName}');
     }
  }

你可以使用 @override 注释来表明你重写了一个成员。
 class A {
    @override
    void noSuchMethod(Invocation mirror) {
       // ...
    }
 }

'''
如果你用 noSuchMethod() 实现每一个可能的 getter 方法,
setter 方法和类的方法,那么你可以使用 @proxy 标注来避免警告。
''
 @proxy
 class A {
    void noSuchMethod(Invocation mirror) {
        // ...
    }
 }

mixins

  • mixins 是一种多类层次结构的类的代码重用。
  • 要使用 mixins ,在 with 关键字后面跟一个或多个 mixin 的名字。用,分开
  • 要实现 mixin ,就创建一个继承 Object 类的子类,不声明任何构造函数,不调用 super 。
class With1 {
  String getName() => 'With1';//三个类都有该方法
  String getAge()=> "With1   10" ;//该类独有
}

class With2 {
  String getName() => 'With2';//三个类都有该方法
  String getColor() => "With2   red";//该类独有
  int getNum()=> 6;//该类和OtherClass都有
  String getFruit()=>"With2   banana";
}

class OtherClass {
  String getName() => 'OtherClass';//三个类都有该方法
  int getNum() => 3; //该类和With2都有
  int getDesk() => 333;//该类独有

  String getPhone()=>"OtherClass   huawei";//该类和子类
  String getFruit()=>"OtherClass   apple";

}

class Child1 extends OtherClass with With1 ,With2 {
  //重写父类
  @override
  String getPhone() {
    return "Child1   iphone";
  }
  @override
  String getFruit() {
    return "Child1  oriange";
  }
}
class Child2 extends OtherClass with With2, With1 {}

void main(){
    print("class Child1 extends OtherClass with With1 ,With2 {}");
    Child1 c1 = Child1();

    //Child1   iphone     重写了函数,调用时用的是自身的函数
    print(c1.getPhone());

    //Child1  oriange     重写了函数,调用时用的是自身的函数
    print(c1.getFruit());

    //333      调用的是OtherClass的函数  With1 With2中没有同名函数
    print(c1.getDesk());
    print(c1.getNum());//6       调用的是With2中的函数
    print(c1.getAge());//With1   10        调用的是With1中的函数
    print(c1.getColor());//With2   red       调用的是With2中的函数

    //With2          调用的是With2中的函数    With2在声明顺序中更靠后
    print(c1.getName());

    print("-----------------------");
    print("class Child2 extends OtherClass with With2, With1 {}");
    Child2 c2 = Child2();
    //OtherClass   huawei     没有重写函数,调用时用的是OtherClass的函数
    print(c2.getPhone());

    //With2   banana    没有重写函数,调用时用的是With2的函数
    //虽然OtherClass也有,但With2在声明顺序中更靠后
    print(c2.getFruit());

    //333     调用的是OtherClass的函数  With1 With2中没有同名函数
    print(c2.getDesk());
    print(c2.getNum());//6     调用的是With2中的函数
    print(c2.getAge());//With1   10       调用的是With1中的函数
    print(c2.getColor());//With2   red      调用的是With2中的函数

    //With1      调用的是With1中的函数    With1在声明顺序中更靠后
    print(c2.getName());
}

隐式接口

  • Z 实现了类X Y ,那么Z中必须重写XY中所有的属性和函数。
  • 与java不同,dart中没有专门定义接口的方式,dart中类即是接口。
  • 一个类可以实现多个接口,也就是可以实现多个类,用implements。
  • 一个类只能继承一个类,用extends。
class X {
  int x= 19;
  void funX(){
    print("X-X");
  }
}
class Y {
  String y = "yyy";
  void funY(){
    print("Y-Y");
  }
}
class Z implements X,Y{
  @override
  int x=33;
  @override
  String y="33333";

  @override
  void funX() {
    print("Z-X");
  }
  @override
  void funY() {
    print("Z-Y");
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容