Dart --类

作者: 小懒豆 | 来源:发表于2019-07-12 19:16 被阅读1次

    类概述

    • 普通类
      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");
      }
    }
    

    相关文章

      网友评论

        本文标题:Dart --类

        本文链接:https://www.haomeiwen.com/subject/nkqkkctx.html