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的实例时,则会报错。
    }
  • 相关阅读:
    xpath定向爬取
    正则表达式的零散知识
    正则表达式中的零宽断言
    Cookies
    一行代码从PDF提取Excel文件
    学习kafka的内容总结
    深度学习模型部署
    舆情情感分析
    关键词提取的几种常用方法总结以及代码实现
    语义预训练模型ERNIE
  • 原文地址:https://www.cnblogs.com/it-tsz/p/12510552.html
Copyright © 2011-2022 走看看