不讲理论,代码实践

一、类的声明与使用

1、声明一个 Person 类

lib/Person.dart 声明了一个 Person class:

class Person {
  // 类属性声明
  String name;
  int age;
  int sex;
  
  // 普通构造函数
  Person(String name, int age, [int sex = 1]) {
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  // 方法声明
  void getInfo() {
    print(
        'My name is ${name}, my age is ${age}, and I am a ${sex == 1 ? 'man' : 'woman'}');
  }

  // 修改类属性
 void changeName(String name) {
    if (name != null) {
      this.name = name;
    }
  }
}

上面的类已经声明结束了,属性、方法和构造函数都有。

2、类的引入

在要使用的 dart 文件中引入 Person 类:

import 'lib/Person.dart';

3、实例化 Person 类

Person p = new Person('ada', 20, 0);
p.getInfo();
p.changeName('postburd');
p.getInfo();

输出结果:

5.jpg

4、私有属性及私有方法

私有属性和方法 只有放在单独的文件 class 中生效

class Person {
// ...
  String _secret; // 私有属性 只有放在单独的文件 class 中生效

// ...
  // 私有方法
  void _run() {
    print('private function _run');
  }

  // 对外暴露私有方法
  void executeRun() {
    this._run();
  }
}

访问私有属性和方法:

print('---------私有属性和方法-----------');
Person p4 = new Person.secret('_secret message');
print(p4.getSecret());
p4.setSecret('new _secret message');
print(p4.getSecret());

6.jpg

5、命名构造函数

命名构造函数允许多个不同名称构造函数的存在,调用不同名称的构造函数,可以实例化出不同的实例。

  // 命名构造函数
  Person.now() {
    print(new DateTime.now());
  }
  Person.setInfo(this.name, this.age, [this.sex]);
  Person.secret(this._secret);

使用命名构造函数:

print('--------命名构造函数------------');
Person p2 = new Person.now();
print(p2);
p2.getInfo();
p2.changeName('postburd');
p2.getInfo();

输出结果:

7.jpg

print('----------命名构造函数----------');
Person p3 = new Person.setInfo('ada', 20, 0);
p3.getInfo();
p3.changeName('postburd');
p3.getInfo();

输出结果:

8.jpg

6、getter和setter

getter 和 setter 可以最大程度的简化值得获取或者格式化以及设置

  get info{
    return 'My name is ${name}, my age is ${age}, and I am a ${sex == 1 ? 'man' : 'woman'}';
  }
  set newName(String name) {
    if(name != null) {
      this.name = name;    
    }
  }

使用 getter 和 setter

print('----------getter和setter----------');
Person p5 = new Person('postbird', 20);
print(p5.info);
p5.newName = 'newNamePostbird';
print(p5.info);

输出结果:

9.jpg

7、初始化构造列表

初始化构造函数可以默认初始化一个值,不过单 class 上没有实际意义

String defaultCounntry;
// 初始化列表
Person(String name, int age, [int sex = 1]):defaultCounntry = 'CN' {
  this.name = name;
  this.age = age;
  this.sex = sex;
}

使用:

print('----------初始化构造列表----------');
Person p6 = new Person('postbird', 20);
print(p6.info);
print(p6.defaultCounntry);

输出结果:

10.jpg

8、简写构造函数

如果构造函数没有特殊逻辑处理,可以使用简写的构造函数:

// 简写构造函数
Person(this.name, this.age, [this.sex]);

二、静态成员

静态方法只能访问静态属性,不能访问非静态属性。

非静态方法可以正常访问静态属性

class Person {
  static String name;
  int age;
  static void setName(String name) {
    Person.name = name;
    // this.age = 20; // error
  }
  void printName() {
    print('name is ${Person.name}');
  }
}


void main() {
  print('------------静态成员-------------------');
  Person p1 = new Person();
  p1.printName();
  Person.setName('postbird');
  p1.printName();
  print(Person.name);
}

输出结果:

11.jpg

三、? 、is 、as 和 .. 操作符

? 操作符用于判断如果实例存在则调用方法,否则不调用

is 用于判断是否归属于某个类的实例或者子类

as 用于声明某个实例当做某个类使用,比如 子类 as 父类

.. 级联操作符用于串联操作

代码示例:

import 'demo6.dart';

class Person {
  String name;
  int age;
  Person(this.name, this.age);

  void printInfo() {
    print('name is ${this.name}, age is ${this.age}');
  }
}


void main() {
  // p.printInfo(); // NoSuchMethodError: The method 'printInfo' was called on null.
  print('----------- ? 条件运算符----------------');
  Person p1;
  p1?.printInfo();
  Person p2 = new Person('postbird', 20);
  p2?.printInfo();
  print('----------- is ---------------');
  if (p2 is Person) {
    p2.name = 'newPers';
  }
  p2.printInfo();
  print(p1 is Person);
  print('----------- as ---------------');
  var p3 = p2;
  // (p3 as Person).name = 'newPtbird';
  // p3.printInfo();
  (p3 as Person).printInfo();
  print('----------- .. 级联操作符---------------');
  Person p4 = new Person('sada', 20);
  p4..name = 'new Name'
    ..age = 22
    ..printInfo();
}

输出结果:

12.jpg

四、extends 继承

子类继承父类使用 extends 关键字,dart 没有多继承

重写方法最好加上 @override 注解,便于协作

子类构造方法中,如果要初始化父类构造方法,使用 super 关键字,比如 Dog(String name, int age, [String nickName]) : super(name, age);

子类中调用父类的方法使用 super.fun()

代码示例

class Animal {
  String name;
  int age;
  Animal(this.name, this.age);
  void speak() {}
  void printInfo() {
    print('My name is ${name}');
  }

  void parentPrint() {
    print('I am parent');
  }
}

class Dog extends Animal {
  String nickName;
  Dog(String name, int age, [String nickName]) : super(name, age);
  @override
  void speak() {
    this.parentPrint();
    super.parentPrint();
    print('wang wang!');
  }

  void setNickName(String name) {
    if (name != null) {
      this.nickName = name;
    }
  }

  get fullInfo {
    return {"name": this.name, "age": this.age, "nickName": this.nickName};
  }
}

void main() {
  print('---------继承------------');
  Dog d = new Dog('qiu', 3, 'kitty');
  d.printInfo();
  d.speak();
  d.setNickName('Nicjski');
  print(d.fullInfo);
}

输出结果:

13.jpg

五、类的 多态

多态举个例子通俗来讲,就是将改变子类实例的类型是父类,父类能够调用子类中同名的方法,输出结果与子类相同,但是不能调用父类没有子类中拥有的方法。

实际上就是将子类的方法覆盖父类的方法。

比如: Animal d1 = new Dog(); 虽然是 new Dog() 但是 d1 的类型是 Animal,因此调用 d1.speak() 时,实际上调用 d1 子类的方法差不多,但是因为 Animal 没有 run 方法,因此不能调用 d1.run()

class Animal {
  speak() {}
}

class Dog extends Animal {
  @override
  speak() {
    print('wang!');
  }

  run() {
    print('dog run!');
  }
}

class Cat extends Animal {
  @override
  speak() {
    print('miao');
  }

  run() {
    print('dog run!');
  }
}

void main() {
  print('---------多态------------');
  Animal d1 = new Dog();
  Dog d2 = new Dog();
  d1.speak();
  // d1.run(); // Error: The method 'run' isn't defined for the class 'Animal'.
  d2.speak();
  d2.run();
}

输出结果:

1.jpg