zoukankan      html  css  js  c++  java
  • Dart(六)类

    Dart(六)类

    Object
    • Object是所有类的父类。
    • Object没有父类。
    • 一个类只能有一个父类。
    • 如果一个类没有显示的用extends去继承一个类,那么默认其继承的是Object。
    类概述
    • 普通类
      1. 变量
        • 实例变量(创建对象后,使用 对象.变量名 调用)
        • 静态变量(用static修饰,使用 类名.变量名 调用)
      2. 函数
        • 实例函数(创建对象后,使用 对象.函数名 调用)
        • 静态函数(用static修饰,使用 类名.函数名 调用)
      3. 构造函数
        • 默认构造函数
        • 自定义构造函数
        • 静态构造函数(使用const修饰的构造函数)
        • 重定向构造函数
        • 工厂构造函数
    • 抽象类
      1. 变量
        • 实例变量(其子类创建对象后,使用 对象.变量名 调用)
        • 静态变量(用static修饰,使用 类名.变量名 调用)
      2. 函数
        • 实例函数(其子类创建对象后,使用 对象.函数名 调用)
        • 静态函数(用static修饰,使用 类名.函数名 调用)
        • 抽象函数(其子类实现该函数,创建对象后,使用对象.函数名 调用)
      3. 不能实例化(工厂构造函数除外)。
    普通类

    声明

    class Class01{
      //变量
      int a; 
      String b;
      var c = 3;
      //函数
      void fun01(int d){
        //...
      }
      String fun02(){
        return b;
      }
    }
    

    创建类的实例,使用new 或const,new对应的是普通的构造函数,const对应的是用const形式的构造函数。

    var class01 = new Class01();
    

    调用实例的属性或函数,使用 . 号

    print(class01.c);
    class01.fun02();
    

    级联操作符 .. , 可以连续调用对象的一些列属性或函数。

        var class02 = new Class01();
        class02
          ..a = 1
          ..b = "a"
          ..c = 33
          ..fun02()
          ..fun01(1);
    
    构造函数:
    • 没有返回值(factory构造方法有返回值)
    • 构造函数名与类名相同

    默认构造函数,如果类中没有显示声明构造函数,那么会默认有个构造函数,默认构造函数是与类同名且无参数无返回值的函数。

    class Class01{
      //变量
      int a; 
      String b;
    //未声明构造函数
    }
    

    所以这个类默认有个构造函数

    Class01(){}
    

    所以可以使用 new 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");//重定向到构造函数
    }
    

    工厂构造函数

    • 使用factory修饰构造函数
    • 构造函数内有返回值,类型是当前类或其子类,此返回值可以是用命名构造函数创建的,也可以是缓存中的。
    • 使用new创建实例
    class Class06{
      int a;
      static Class06 instance ;  //这里创建了一个单例
      factory Class06(int a){//这里的构造函数用factory修饰,使用new时,不再是创建一个全新的实例了,而是通过函数体内return获取到实例
        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);
    }
    
    set get方法
    • 使用 set get修饰属性
    • 该属性不是真实存在,而是类似于一个函数,该函数内可以对类的其他属性和方法进行操作。
    • 读取该属性值时 调用的get
    • 对该属性赋值时,调用的set
    class Class08{
      int hands;
      int feet;
      
      num get persons => hands / 2;
          set persons(num n){
              hands=n*2;
              feet=n*2;
          } 
    }
    volid main(){
        var class08 = new Class08();
        class08.persons = 3;//这里就调用了set方法,进而对hands feet赋值了
        print(class08.hands);
    }
    
    抽象类
    • 使用abstract修饰类。
    • 可定义实例方法。
    • 可定义抽象方法,抽象方法没有函数体。
    • 抽象类不能实例化(工厂构造函数除外)。
    • 子类继承抽象类后,必须实现所有抽象方法,除非子类也是抽象类。
    • 只有抽象类能定义抽象方法。
    //定义抽象类
    abstract class Class09{
      void fun01();//定义抽象方法
    }
    //继承抽象类
    class Class10 extends Class09{
      @override
      void fun01() {//实现抽象方法
        print("aaa");
      }
    }
    void main(){
     var c10 = new Class10();
     c10.fun01();
    }
    
    静态变量和静态函数
    • 使用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 Week{
      Monday,
      Tuesday,
      Wednesday,
      Thursday,
      Friday,
      Saturday,
      Sunday
    }
    
    //属性values 获取所有枚举值
      List<Week> list = Week.values;
    
      list.forEach((e){
        print(e);//打印枚举
    //     Week.Monday
    //     Week.Tuesday
    //     Week.Wednesday
    //     Week.Thursday
    //     Week.Friday
    //     Week.Saturday
    //     Week.Sunday
      });
    
      list.forEach((e){
        print(e.index);//属性index  表示该枚举值在定义时的序号
    //     0
    //     1
    //     2
    //     3
    //     4
    //     5
    //     6
      });
    
      var day = Week.Friday;
      switch(day){
        case Week.Monday:
          break;
        case Week.Tuesday:
          break;
        case Week.Wednesday:
          break;
        case Week.Thursday:
          break;
        case Week.Friday:
          break;
        case Week.Saturday:
          break;
        case Week.Sunday:
          break;
        default:
          break;
      }
    
    继承
    • 使用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";//重写了父类的属性
      //实现了父类的抽象函数
      
    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函数
      
    mixins
    • 类在Dart中只能继承一个父类。
    • mixin可理解为让类实现了继承多个父类的效果,但不是多继承,而是其目的是实现代码重用。

    声明一个with类

    • 跟声明普通类一样的方式。
    • 区别在于,不声明构造函数,也不使用静态函数或变量。
    • 纯粹的属性和函数。

    怎么使用?子类声明时

    • 后跟with+类名
    • with后可跟多个类,用“,”分开
      看个例子:
    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 {
      //重写父类
      
    void main(){
        print("class Child1 extends OtherClass with With1 ,With2 {}");
        Child1 c1 = Child1();
        print(c1.getPhone());//Child1   iphone     重写了函数,调用时用的是自身的函数
        print(c1.getFruit());//Child1  oriange     重写了函数,调用时用的是自身的函数
        print(c1.getDesk());//333      调用的是OtherClass的函数  With1 With2中没有同名函数
        print(c1.getNum());//6       调用的是With2中的函数
        print(c1.getAge());//With1   10        调用的是With1中的函数
        print(c1.getColor());//With2   red       调用的是With2中的函数
        print(c1.getName());//With2          调用的是With2中的函数    With2在声明顺序中更靠后
    
        print("-----------------------");
        print("class Child2 extends OtherClass with With2, With1 {}");
        Child2 c2 = Child2();
        print(c2.getPhone());//OtherClass   huawei     没有重写函数,调用时用的是OtherClass的函数
        print(c2.getFruit());//With2   banana    没有重写函数,调用时用的是With2的函数,虽然OtherClass也有,但With2在声明顺序中更靠后
        print(c2.getDesk());//333     调用的是OtherClass的函数  With1 With2中没有同名函数
        print(c2.getNum());//6     调用的是With2中的函数
        print(c2.getAge());//With1   10       调用的是With1中的函数
        print(c2.getColor());//With2   red      调用的是With2中的函数
        print(c2.getName());//With1      调用的是With1中的函数    With1在声明顺序中更靠后
    }
    

    终极理解:

    • A extends B with C,D{}
    • A 继承了B 并拥有了C和D所有的属性和函数,可以用A的实例直接调用CD的属性方法。
    • 如果B有函数fun1,A重写了这个函数 那么以后A的实例调用的fun1,都是A重写后的方法。
    • 如果B有函数fun1,CD中也有函数fun1,A重写了这个函数 那么以后A的实例调用的fun1,都是A重写后的方法。
    • 如果B有函数fun1,CD中也有函数fun1,A没有重写这个函数 那么以后A的实例调用的fun1,是声明方法时最后的那个类的函数,比如“A extends B with C,D”,那么就是D中的fun1,如果是“A extends B with D,C”,那么就是C中的fun1。也就是说优先级是从后向前的(前提是子类没有重写函数)。
    隐式接口
    • 与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{
      
    • Z 实现了类X Y ,那么Z中必须重写XY中所有的属性和函数。
    • 如果XY中有同名方法,但是参数个数或返回值不同呢?亲测了下,dart会提示你Z改用with,有冲突,已经无法处理了。
    • 如果XY中有方法,其返回值、名字、参数个数和类型都一样,那么在Z中重写一次就行。
    extends、with、implements关系
    • 三者可同时存在,但声明时有先后顺序
    class A extends B with C implements D{}
    
    • 三者作用不同,extends是继承体系,单继承;mixins是做扩展功能,复用代码,可以理解为import了一个工具类;implements是接口实现
    as 和 is
    • as ,A as B,将A转为B类型,然后可以使用B的属性方法了,前提是B是A的子类。
    • is,A is B,A是否是B的实例对象,当A是B或B的子类的实例对象时,返回true。当进行判断且为true时,同时进行了转换。
    class A {
      int getSum(int a,int b){
        return a+b;
      }
    }
    class B extends A{
      int getSub(int a,int b){
        return a-b;
      }
    }
    
    main(){
      A a = new B();
      // a.getSum(1,3);// 没问题,调用A的方法
      // a.getSub(1,3);// 报错,调用B的方法。
      if (a is B){
        a.getSub(1,3);//没问题, a 是 B的实例对象,因此判断 a is  B 后,可以调用B的方法。
      }
      var c = a as B;// 将a 转为 B的实例,降维
      c.getSub(1,3);//  这里a的确是B的实例对象,因此没问题,但是当a不是B的实例时,则会报错。
    }
  • 相关阅读:
    EXTJS 4.2 资料 控件之checkboxgroup的用法(静态数据)
    EXTJS 4.2 资料 控件之Window窗体相关属性的用法
    EXTJS 4.2 资料 控件之textfield文本框加事件的用法
    Entity Framework 学习笔记(一)之数据模型 数据库
    EXTJS 4.2 资料 控件之checkboxgroup的用法(动态数据)
    EXTJS 4.2 资料 控件之Grid 列鼠标悬停提示
    Entity Framework 学习笔记(二)之数据模型 Model 使用过程
    EXTJS 4.2 资料 控件之radiogroup 的用法
    EXTJS API
    vue移动端弹框组件,vue-layer-mobile
  • 原文地址:https://www.cnblogs.com/it-tsz/p/12510552.html
Copyright © 2011-2022 走看看