Dart 学习笔记 (七) 类

322 阅读7分钟

概念

Dart所有的东西都是对象,所有的对象都继承自Object类。

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

一个类通常由属性和方法组成。

构造函数

在dark中一运行就执行的方法被称为构造函数

默认构造函数只能写一个

class Person {
  String name = "张三";
  int age = 23;
  //- 默认构造函数
  Person() {
    print("这是构造函数里面的内容 这个方法在实例化的时候触发");
  }
  
  //- 参数的传递
  Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  
  //- 默认构造函数的简写
  Person(this.name, this.age);
}

void main() {
  //- 不传参数的调用方法
  Person p1 = new Person();
  
  //- 传递参数的调用方法
  Person p1 = new Person("张三", 20);
  p1.name;

  Person p2 = new Person("李四", 25);
  p2.name;
}

命名构造函数可以写多个

class Person {
  String name = "";
  Person.now() {
    print('我是命名构造函数');
  }
  Person.setName(String name) {
    this.name = name;
    print("${this.name}");
  }
}

void main() {
  Person p1 = new Person.now();
  Person p2 = new Person.setName("李四");
}

私有属性和方法

Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合, 但是我们可以使用_把一个属性或者方法定义成私有。

// 单独的一个 person.dark
class Person {
  String _name = "";
  int age = 0;

  Person(this._name, this.age);

  void printInfo() {
    print("${this._name}---${this.age}");
  }

  String getName() {
    return this._name;
  }

  void _run() {
    print('这是一个私有方法');
  }

  execRun() {
    this._run(); //- 类里面方法的相互调用
  }
}
// main.dark
import "demo/Person.dart";

void main() {
  Person p2 = new Person("李四", 20);

  print(p2.getName());
  p2.execRun(); //- 通过execRun调用私有方法_run();
}

getter 和 setter 的使用

class Rect {
  num height;
  num width;
  Rect(this.height, this.width);
  
  //area() {
  //  return this.height * this.width;
  //}
  
  get area {
    return this.height * this.width;
  }

  set areaHeight(value) {
    this.height = value;
  }
}

void main() {
  Rect r = new Rect(10, 2);
  // print("面积:${r.area}");
  r.areaHeight = 6;
  print("面积:${r.area}"); // getter 调用
  // print("面积:${r.area()}"); // 方法调用
}

初始化值

class Rect {
  num height;
  num width;
  Rect(): height = 2,width = 11 {}

  area() {
    return this.height * this.width;
  }
}

void main() {
  Rect r = new Rect();
  print(r.area());
}

静态成员

  1. 使用static 关键字来实现类级别的变量和函数
  2. 静态方法不能访问非静态成员,非静态方法可以访问静态成员
  3. 只能通过类来进行访问
class Person {
  static String name = "张三";
  int age = 20;

  static void show() {
    print(name);
  }

  void printInfo() {
    /* 非静态方法可以访问静态成员以及非静态成员 , 访问静态属性以及调用静态方法不需要使用this*/
    print(name); // 访问静态属性
    print(this.age); // 访问非静态属性
    // show();
  }
}

void main() {
  Person p = new Person();
  p.printInfo();
}

封装 、继承、多态

面向对象的三大特性:封装 、继承、多态

继承

Dark中的类的继承:

  1. 子类使用extends关键词来继承父类
  2. 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
  3. 子类能复写父类的方法 getter和setter
class Person {
  String name;
  num age;
  //- 构造函数本身是没有办法进行继承的
  Person(this.name, this.age);
  void printInfo() {
    print("${this.name}---${this.age}");
  }
}

class Web extends Person {
  //- 子类的构造函数给父类的构造函数传递参数
  //- 执行子类的构造函数之前,把子类传递过来的参数赋值给父类(super表示赋值给父类的构造函数)
  Web(String name, num age) : super(name, age);
}

void main() {
  Web w = new Web("张三", 20);
  w.printInfo();
}
class Person {
  String name;
  num age;
  //- 构造函数本身是没有办法进行继承的
  Person(this.name, this.age); // 匿名构造函数
  Person.fn(this.name, this.age); // 命名构造函数
  void printInfo() {
    print("${this.name}---${this.age}");
  }
}

class Web extends Person {
  String sex = "";
  //- 子类的构造函数给父类的构造函数传递参数
  //- 执行子类的构造函数之前,把子类传递过来的参数赋值给父类(super表示赋值给父类的构造函数)
  
  //- 匿名构造函数传递参数
  Web(String name, num age, String sex) : super(name, age) {
    this.sex = sex;
  }
  //- 命名构造函数传递参数
  Web(String name, num age, String sex) : super.fn(name, age) {
    this.sex = sex;
  }
  
  run() {
    print("${this.name} --- ${this.age} --- ${this.sex}");
  }
}

void main() {
  Web w = new Web("张三", 20, "女");
  w.printInfo();
  w.run();
}

  1. 子类可以覆写父类的方法,覆写时建议使用 @override 表示是子类覆写父类的方法,也可以不进行添加
  2. 子类也可以调用父类的方法
class Person {
  String name;
  num age;
  Person(this.name, this.age);
  void printInfo() {
    print("${this.name}---${this.age}");
  }

  work() {
    print("${this.name}在工作...");
  }
}

class Web extends Person {
  Web(String name, num age) : super(name, age);
  run() {
    print("run");
    super.work(); //- 子类调用父类的方法
  }

  //- 覆盖父类的方法,建议在覆写的时候加@override(可以不写)

  @override
  void printInfo() {
    print("子类覆盖:${this.name} --- ${this.age}");
  }
}

main() {
  Web w = new Web("李四", 20);
  w.printInfo();
  w.run();
}

抽象

Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。

  1. 抽象类通过abstract 关键字来定义
  2. Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
  3. 如果子类继承抽象类必须得实现里面的抽象方法
  4. 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
  5. 抽象类不能被实例化,只有继承它的子类可以

extends抽象类 和 implements的区别:

  1. 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
  2. 如果只是把抽象类当做标准的话我们就用implements实现抽象类
//- 抽象类
//- 抽象类定义的方法,在子类里面必须定义
//- 抽象类是没有办法进行直接实例化的,只有继承子类才可以实例化
abstract class Animal {
  eat(); //- 抽象方法; 不定义函数体 ; 要求子类里面都要有eat方法,里面就需要定义抽象方法
  //- 普通方法定义
  printInfo() {
    print("hello");
  }
}

class Dog extends Animal {
  @override
  eat() {
    print("Dog");
  }
}

main() {
  Dog d = new Dog();
  d.eat();
  d.printInfo();
  
  // Animal a=new Animal();   //抽象类没法直接被实例化
}

多态

Datr中的多态:

  1. 允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
  2. 子类的实例赋值给父类的引用。
  3. 通俗讲:多态就是父类定义一个方法不去实现,让子类来进行实现,每个子类有不同的表现就是多态
abstract class Animal{
  eat();   //抽象方法 
}

class Dog extends Animal{
  @override
  eat() {
     print('小狗在吃骨头');
  }
  run(){
    print('run');
  }
}
class Cat extends Animal{
  @override
  eat() {   
    print('小猫在吃老鼠');
  }
  run(){
    print('run');
  }
}

main(){

  // Dog d=new Dog();
  // d.eat();
  // d.run();


  // Cat c=new Cat();
  // c.eat();

  Animal d=new Dog();
  d.eat();

  Animal c=new Cat();
  c.eat();
}

接口

和Java一样,dart也有接口,但是和Java还是有区别的。

首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。 同样使用implements关键字进行实现。 但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。 而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。 建议使用抽象类定义接口。

abstract class Db {
late String uri;
add(String data);
save();
delete();
}

class Mysql implements Db {
@override
String uri;
Mysql(this.uri);

@override
add(String data) {
  // TODO: implement add
  print(data);
}

@override
delete() {
  // TODO: implement delete
  print("delete");
}

@override
save() {
  // TODO: implement save
  print("save");
}
}

main() {
Mysql mysql = new Mysql('xxxx');
mysql.add('123');
}

一个类实现多个接口

abstract class A {
  printA();
}

abstract class B {
  printB();
}

class C implements A, B {
  @override
  printA() {
    print('printA');
  }

  @override
  printB() {
    print('printB');
  }
}

main() {
  C c = new C();
  c.printA();
  c.printB();
}

mixin

mixins的中文意思是混入,就是在类中混入其他功能。

在Dart中可以使用mixins实现类似多继承的功能

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:

  1. 作为mixins的类只能继承自Object,不能继承其他类
  2. 作为mixins的类不能有构造函数
  3. 一个类可以mixins多个mixins类
  4. mixins绝不是继承,也不是接口,而是一种全新的特性
// mixin
class A {
 String info = "this is A";
 printA() {
   print("A");
 }
}

class B {
 printB() {
   print("B");
 }
}

class C with A, B {}

main() {
 C c = new C();
 c.printA();
 c.printB();
 print(c.info);
}
//- 作为mixins的类只能继承自Object,不能继承其他类
class Person {
 printInfo() {
   print("这是一个person类");
 }
}

//- A如果继承了Person就不可以封装成mixin了
class A extends Person {
 String info = "this is A";
 printA() {
   print("A");
 }
}
//- 作为mixins的类不能有构造函数
//- 但是可以有另外一种写法
class Person {
 String name;
 num age;
 Person(this.name, this.age);
 printInfo() {
   print("$name --- $age");
 }
}

class A {
 String info = "this is A";
 printA() {
   print("A");
 }

 void run() {
   print("A Run");
 }
}

class B {
 printB() {
   print("B");
 }

 void run() {
   print("B Run");
 }
}

//- 即继承了Person 还有使用了mixin A,B的属性和方法

//- 如果mixinA,B有相同的方法,with后面的顺序不同,C实例化调用得到的结果也不同,后面的回覆盖前面的;
class C extends Person with A, B {
 C(String name, num age) : super(name, age);
}

main() {
 C c = new C("李四", 20);
 // c.printA();
 // c.printB();
 // c.printInfo();
 // print(c.info);
 c.run();
}

//- 类型
class A {
 printA() {
   print("A");
 }

 void run() {
   print("A Run");
 }
}

class B {
 printB() {
   print("B");
 }

 void run() {
   print("B Run");
 }
}

class C with B, A {}

main() {
 C c = new C();

 print(c is C); // true
 print(c is A); // true
 print(c is B); // true
}