Dart 类与对象

类是通过 class 关键字声明的代码段,包含属性和方法

  属性:用来描述类的变量
  方法:类中的函数称为类的方法

对象是类的实例化结果(var obj = new MyClass())

编程方式
  面向对象编程(OOP)
  面向过程编程(POP)
// 声明类
class Person {
  // 类的属性
  String name = 'Roger';
  // 类的方法
  void getInfo() {
    print(this); // Instance of 'Person'
    print('My name is $name'); // My name is Roger
    print('我的名字叫 ${this.name}'); // 我的名字叫 Roger
  }
}

void main() {
  // 实例化类,然后得到一个对象
  Person p = new Person();
  // 访问类中的属性
  print(p.name); // Roger
  // 访问类的方法
  p.getInfo();
}

 

构造器(构造函数)

默认构造函数
  与类同名的函数,在实例化时,自动被调用
class Point {
  num x, y;
  // 默认构造函数
  Point() {
    print('这是默认的构造函数,实例化时,会第一个被调用。');
  }
}

void main() {
  Point p = new Point();
  print(p.x);
  // 这是默认的构造函数,实例化时,会第一个被调用。
  // null
}
class Point {
  num x, y;
  // 默认构造函数
  // Point() {
  //   // this可以省略
  //   x = 0;
  //   y = 0;
  // }

  Point(num x, num y) {
    // 当命名指向有歧义时,this 不能省略
    // x = x;
    // y = y;
    this.x = x;
    this.y = y;
  }
}

void main() {
  Point p = new Point(3, 4);
  print(p.x); // 构造器中参数与类属性同名,省略this时,输出结果为 null;加上this,输出结果为 3
}
class Point {
  num x, y;
  // 默认构造函数的简写
  Point(this.x, this.y);
}

void main() {
  Point p = new Point(2, 4);
  print(p.x); // 2
}

 

命名构造函数
  在类中使用命名构造函数(类名.函数名)实现多个构造器,可以提供额外的清晰度
class Person {
  String name;
  int age;

  // 默认构造函数
  Person(this.name, this.age);

  // 命名构造函数 -- 提供 Person 类的示例
  Person.example() {
    name = '张三';
    age = 23;
  }

  // 命名构造函数 -- 使用命名参数传值
  Person.namedParameter({name, age}) {
    this.name = name;
    this.age = age;
  }

  void getInfo() {
    print('姓名:$name, 年龄:$age');
  }
}

void main() {
  Person p1 = new Person('李四', 24);
  Person p2 = new Person.example();
  Person p3 = new Person.namedParameter(name: '光头强', age: 45);

  p1.getInfo(); // 姓名:李四, 年龄:24
  p2.getInfo(); // 姓名:张三, 年龄:23
  p3.getInfo(); // 姓名:光头强, 年龄:45
}

常量构造函数
  如果类生成的对象不会改变,可以通过常量构造函数使这些对象成为编译时常量
class ConstantClass {
  // 属性必须通过 final 声明
  final String book;
  // const String author; // Only static fields can be declared as const
  final String author;

  // 常量构造函数,必须通过 const 声明
  const ConstantClass(this.book, this.author);
}

void main() {
  // 声明不可变对象,必须通过 const 关键字
  var c1 = const ConstantClass('西游记', '吴承恩');
  var c2 = const ConstantClass('西游记', '吴承恩');
  print(c1 == c2); // true

  // 常量构造函数,可以当作普通构造函数使用
  var c3 = new ConstantClass('西游记', '吴承恩');
  var c4 = new ConstantClass('西游记', '吴承恩');
  print(c3 == c4); // false

  // 实例化时,new关键字可以省略
  var c5 = new ConstantClass('西游记', '吴承恩');
  var c6 = new ConstantClass('西游记', '吴承恩');
  print(c5 == c6); // false
}

 

工厂构造函数
  通过 factory 声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例
class Car {
  int wheels;

  static Car instance;

  // 命名构造函数
  Car.newCar(this.wheels);

  // 工厂构造函数 -- 接受一个可选参数并赋默认值4
  factory Car([int wheels = 4]) {
    // 工厂构造函数中,不能使用 this 关键字
    // print(this.wheels); // Invalid reference to 'this' expression

    // 第一次实例化
    if (Car.instance == null) {
      Car.instance = new Car.newCar(wheels);
    }
    // 非第一次实例化
    return Car.instance;
  }
}

void main() {
  // Car c1 = new Car();
  // Car c2 = new Car(6);
  // print(c1.wheels); // 4
  // print(c2.wheels); // 4

  Car c1 = new Car(6);
  Car c2 = new Car();
  print(c1.wheels); // 6
  print(c2.wheels); // 6
  print(c1 == c2); // true
}

 

访问修饰

Dart 没有访问修饰符(public, protected, private),在 Dart 类中,默认的访问修饰符是公开的(即 public)

如果要使用私有属性(private),需要同时满足以下两个条件:
(1)、属性或方法以_(下划线)开头
(2)、只有把类单独抽离出去,私有属性和方法才起作用
class Person {
  String name;

  // 声明私有属性
  num _age = 8;

  Person(this.name);

  num getAge() {
    return this._age;
  }
}
import 'lib/Person.dart';

void main() {
  Person p = new Person('Rogers');
  print(p.name); // Rogers

  // 访问私有属性
  // print(p._age); // The getter '_age' isn't defined for the type 'Person'.

  print(p.getAge()); // 8
}

 

Getter与Setter

Getter(获取器)是通过 get 关键字修饰的方法
  函数没有小括号,访问时也没有小括号(像访问属性一样访问方法)

Setter(修改器)是通过 set 关键字修饰的方法
  访问时,像设置属性一样给函数传参
class Circle {
  final double PI = 3.1415926;
  num r;

  Circle(this.r);

  // 使用 get 声明的方法,不能有小括号
  // num get area() { // Getters must be declared without a parameter list.
  num get area {
    return this.PI * this.r * this.r;
  }

  set setR(r) {
    this.r = r;
  }
}

void main() {
  Circle c = new Circle(3);

  // 通过 Setter 修改属性
  c.setR = 10;

  print(c.area); // 314.15926
}

 

初始化列表

作用:在构造函数中设置属性的默认值

时机:在构造函数体执行之前执行

语法:使用逗号分隔初始化表达式

场景:常用于设置 final 常量的值
class Rect {
  double height;
  double width;

  // 方案一:使用可选参数赋默认值
  // Rect([double height = 3.0, double width = 2.0]) {
  //   this.height = height;
  //   this.width = width;
  //   print('height: $height, width: $width');
  // }

  // 初始化列表
  Rect()
      : height = 3.0,
        width = 2.0 {
    print('height: $height, width: $width');
  }
}

void main() {
  Rect r = new Rect(); // height: 3.0, width: 2.0
}
class Point {
  double x, y, z;

  Point(this.x, this.y, this.z);

  // 初始化列表的特殊用法(重定向构造函数)
  Point.twoD(double x, double y) : this(x, y, 0);
}

void main() {
  // 实例化坐标
  Point p1 = new Point(1, 2, 3);
  print(p1.z); // 3.0

  Point p2 = new Point(1, 2, 0);
  print(p2.z); // 0.0
}

 

static

static 关键字用来指定静态成员
  通过 static 修饰的属性是静态属性
  通过 static 修饰的方法是静态方法

静态成员可以通过类名称直接访问(不需要实例化)
  实例化是比较消耗资源的,声明静态成员,可以提高程序性能

静态方法不能访问非静态成员,非静态方法可以访问静态成员
  静态方法中不能使用 this 关键字
  不能使用 this 关键字访问静态属性
class Person {
  static String name = 'Rogers';
  int age = 16;

  void printInfo() {
    // 不能通过this关键字访问静态属性
    // print(this.name);

    // 非静态方法,可以访问静态属性
    print(name);
    print(age);

    // 非静态方法,可以访问静态方法
    printName();
  }

  static void printName() {
    // 不能通过this关键字访问静态属性
    // print(this.name);
    print(name);

    // 静态方法中不能访问非静态属性
    // print(age);
  }
}

void main() {
  // 静态成员,可以通过类名直接访问
  print(Person.name); // Rogers
  Person.printName(); // Rogers

  // 不能通过类名称,直接访问非静态方法
  // Person.printInfo();

  Person p = new Person();
  // 不能通过实例化对象访问静态属性
  // print(p.name);
  p.printInfo();
}

 

元数据

元数据以 @ 开头,可以给代码标记一些额外的信息
  元数据可以用在库,类,构造器,函数,字段,参数或变量声明的前面

@override(重写)
  某个方法添加该注解后,表示重写了父类中的同名方法

@required(必填)
  可以通过 @required 来注解 Dart 中的命名参数,用来指示它是必填参数

@deprecated(弃用)
  某个类或某个方法加上该注解后,表示这个类或方法不再建议使用
class Phone {
  // 表示这是旧版本中的开机方法,会在后续的迭代版本中删除
  @deprecated
  activate() {
    turnOn();
  }

  turnOn() {
    print('开机');
  }
}

void main() {
  Phone p = new Phone();
  p.activate();
}

 

posted @ 2022-04-26 10:19  rogerwu  阅读(122)  评论(0编辑  收藏  举报