Flutter3-面向对象

类和对象

  • 使用class关键字声明一个类
  • 可以使用new跟上构造函数
  • 所有的对象都继承Object
  • 声明一个类的成员变量要有默认值,如果没有默认值需要写上?代表可选类型。
  • Dart中默认生成gettersetter方法
  • 属性和方法都通过点语法访问
  • final修饰的属性,必须定义初始值
  • 如果没有赋值初始值,可以在构造函数中添加
void main() {
  SJPerson person = SJPerson();
  person.name = 'sj';
  person.age = 18;
  person.run();
}

class SJPerson {
  String? name;
  int? age;
  // SJPerson(this.name);
  void run() {
    print('name:$name, age:$age');
  }
}

作用域权限

  • 同一份文件中可以随意访问
  • 不同文件中使用_开头的成员变量和方法,不能被外界访问
// sj_person.dart
class SJPerson {
  String? _name;
  int? _age;
  // SJPerson(this.name);
  void _run() {
    print('name:$_name, age:$_age');
  }

  void initValue(String name, int age) {
    _name = name;
    _age = age;
  }

  void printP() {
    _run();
  }
}
// main.dart
import 'sj_person.dart';

void main() {
  SJPerson person = SJPerson();
  person.initValue('sj', 18);
  person.printP();

  Animal a = Animal();
  a._name = '123';
}

class Animal {
  String? _name;
}

构造函数

类默认有一个构造函数,如果我们自定义了构造函数,默认的构造函数就没有作用了。
自定义构造函数给成员变量赋值,可以使用this.语法糖直接赋值。

void main() {
  SJTeacher t = SJTeacher('jx', 30);
}

class SJTeacher {
  String? name;
  int? age;
  SJTeacher(this.name, this.age);
}

命名构造函数

void main() {
  SJPerson person = SJPerson.withName(16);
}

class SJPerson {
  String? _name;
  int? _age;
  SJPerson(this._name);

  SJPerson.withName(this._age);
}

使用final修饰的好处是,代表这个成员是常量,如果一个类的成员都是final修饰,构造函数前可以加const修饰,这时我们再创建出来的对象就是常量对象,可以节约内存。

class SJTeacher {
  final String name;
  final int age;
  const SJTeacher(this.name, this.age);
}

单利

构造方法正常是不用写返回对象的,如果想返回对象,需要再方法前写上factory,工厂构造方法。

class FactoryClass {
  static FactoryClass? instance;

  factory FactoryClass() {
    if (instance == null) {
      instance = FactoryClass._init();
    }
    return instance!;
  }
  /// 私有的命名构造函数
  FactoryClass._init();
}

简化如下:

void main() {
  FactoryClass c1 = FactoryClass();
  FactoryClass c2 = FactoryClass();
  print(c1 == c2);
}

class FactoryClass {
  static FactoryClass? _instance;

  factory FactoryClass() => _instance ??= FactoryClass._init();

  /// 私有的命名构造函数
  FactoryClass._init();
}

初始化列表

构造函数后面加:,后面的内容就是初始化列表。
目的:

  1. final变量赋值,它会在初始化之前给列表变量赋值
  2. 校验传递的值,这是最常用也是最主要的功能
class Person {
  String name;
  int age;
  final height;
  Person(this.name, a, h)
      : height = h,
        age = a,
        assert(h >= 0),
        assert(a > 0) {
    print("hahahhaha");
  }
  Person.init2(this.name, a, h)
      : height = h,
        age = a;
}

类方法

  • 静态属性、静态方法用类名直接访问。
  • 静态方法不能访问非静态成员。静态方法是类对象调用的,非静态成员是实例对象初始化后才出来的,这时候还没有实例对象,所以不能访问。
  • 实例方法可以直接访问静态属性。实例对象创建时候,静态属性一定在,所以可以访问。
  • 常量属性需要用static修饰
void staticDemo() {
  StaticClass.count;
  StaticClass.sum(2);
  StaticClass s = StaticClass();
  print(s.sum2(3));
}

class StaticClass {
  // 静态属性
  static int count = 1;
  int count2 = 2;

  static const String name = 'sj';

  /// 静态方法
  static sum(int a) {
    return a + count;
  }

  int sum2(int a) {
    return a + count + count2;
  }
}

对象操作符

var声明变量是动态类型,值可能为null,这时直接执行方法可能会报错,我们把变量后面加个?执行就可以了。

void dynamicDemo() {
  var s;
  s = StaticClass();
  s.sum2(2);
  s = null;
  s?.sum2(2);
}

强制类型转换使用as,转换完后面就能用这个转换的类型了。
使用if判断类型,if里面也可以直接使用此类型。

void mapDemo() {
  var s = Object();
  s = StaticClass();
  if (s is StaticClass) {
    print(s.sum2(2));
  }
  // print((s as StaticClass).sum2(2));
  // print(s.sum2(2));
}

使用..链式编程

void chainedDemo() {
  StaticClass s = StaticClass();
  s..count2 = 10..sum2(2);
}

继承

/**
 * Dart中的继承
 * 使用extends继承一个类
 * 子类会继承除了构造方法意外的属性和方法
 * 默认构造方法会自动继承
 * 如果是有参数或者有名字的构造方法,子类需要显性使用super,实现一个即可
 * Dart是单继承
 * 子类重写父类方法使用@override,不写可以,但是不建议
 * super使用可以和初始化列表一起,super要放到最后
 * */

void extendsDemo() {
  S2 s = S2('sj');
  print(s);
}

class S1 {
  S1.initValue();
  S1(this.age);
  void run() {
    print('run');
  }

  int age = 10;
}

class S2 extends S1 {
  final String name;
  // S2.initValue() : super.initValue();
  S2(String n)
      : name = n,
        super.initValue();
  @override
  void run() {
    // TODO: implement run
    super.run();
  }

  // Object的toString方法类似OC的description方法
  @override
  String toString() {
    // TODO: implement toString
    return 'S2 extends S1';
  }
}

抽象类

/**
 * 抽象类
 * 不能被实例化的类,使用abstract修饰
 * 子类可以被实例化,子类必须实现父类的抽象方法
 * 多态对象不用判断类型,因为子类必须实现父类的抽象方法
 * 子类可以实现多个抽象类,使用implements,实现需要实现所有方法和属性
 * */
abstractDemo() {
  SubClass a = SubClass();
  a.sum(10, 20);
}

abstract class AbstractClass {
  /// 这就是抽象方法
  int sum(int a, int b);
}

abstract class AbstractClass1 {
  /// 这就是抽象方法
  int minus(int a, int b);
}

class NormalClass {
  var name;
  void run() {}
}

class SubClass implements AbstractClass, AbstractClass1, NormalClass {
  @override
  int sum(int a, int b) {
    return a + b;
  }

  @override
  int minus(int a, int b) {
    return a - b;
  }

  @override
  var name;

  @override
  void run() {}
}

Mixins 混入

/**
 * 混入
 * 说白了就是多继承
 * 混入如果有一样的方法,会执行最后一个混入的类的方法
 * 作为混入的类,是不能实现构造方法的,且不能继承非Object类
 * */
mixinsDemo() {
  DClass d = DClass();
  d.a();
  // d.b();
  // d.c();
}

class AClass {
  AClass();
  a() => print('a ...');
}

class BClass {
  a() => print('b ...');
}

class CClass {
  a() => print('c ...');
}

// class DClass extends AClass with BClass, CClass {}

// 如果DClass没有成员和方法,可简写成下面
class DClass = AClass with BClass, CClass;

重载操作符

使用operayor

operatorDemo() {
  OperatorClass o1 = OperatorClass(18);
  OperatorClass o2 = OperatorClass(15);
  print(o1 > o2);
}

class OperatorClass {
  int age;
  OperatorClass(this.age);
  bool operator >(OperatorClass o) => this.age > o.age;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容