三.Flutter之Dart语法(类和对象)

一.类和对象:

Dart是一个面向对象的语言,面向对象中非常重要的概念就是类,类产生了对象。

1.类的定义
/**
 * 在Dart中,定义类用class关键字
 * 类通常有两部分组成:成员(member)和方法(method)。
 * 定义类的伪代码如下:
 * class 类名 {
 *   类型 成员名;
 *   返回值类型 方法名(参数列表) {
 *       方法体
 *   }
 * }
 * 
 * 这里有一个注意点: 我们在方法中使用属性(成员/实例变量)时,并没有加this;
 * Dart的开发风格中,在方法中通常使用属性时,会省略this,但是有命名冲突时,this不能省略
 * 
 * 
 * 当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法
 * 下面的Person中我们就是在调用这个构造方法.
 * 我们也可以根据自己的需求,定义自己的构造方法:
 * 注意:**当有了自己的构造方法时,默认的构造方法将会失效,不能使用
 * 1.当然,你可能希望明确的写一个默认的构造方法,但是会和我们自定义的构造方法冲突;
 * 2.这是因为Dart本身不支持函数的重载(名称相同, 参数不同的方式)
 */
main(List args) {
  // var p = Perosn();
  var p = Perosn("ws", 10);
  print(p.name); //ws
  print(p.age); //10
}

class Perosn {
  String name;
  int age;
  //普通构造方法
  // Perosn(String name, int age) {
  //   this.age = age;
  //   this.name = name;
  // }
  //语法糖
  Perosn(this.name, this.age);
}
2.构造方法:
  • 普通构造方法/命名构造方法
/**
 * 当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法
 * 下面的Person中我们就是在调用这个构造方法.
 * 我们也可以根据自己的需求,定义自己的构造方法:
 * 注意:**当有了自己的构造方法时,默认的构造方法将会失效,不能使用
 * 1.当然,你可能希望明确的写一个默认的构造方法,但是会和我们自定义的构造方法冲突;
 * 2.这是因为Dart本身不支持函数的重载(名称相同, 参数不同的方式)
 *
 *
 *
 * Object 和dynamic的区别
 * Object调用不属于自己的方法,编译时会报错
 * dynamic调用不属于自己的方法,编译时不会报错 但是运行时会报错
 * 
 * dynamic它是一种类型 是一个明确类型 和 String int等一样
 */
main(List args) {
  //创建person对象
  // var p = Perosn();
  // var p = Perosn("ws", 10);
  var p = Perosn.withNameAgeHeight("ws", 10, 190);
  print(p.toString()); //ws 10 190.0

// Object 和dynamic的区别
  // ws_dynamicAndObjectAction();

  var p1 = Perosn.fromMap({"name": "ws", "age": 29, "height": 1.78});
  //重写tostring之前
  print(p1); //Instance of 'Perosn'
  //重写tostring之后
  print(p1); //ws 29 1.78
}

//Object 和dynamic的区别
ws_dynamicAndObjectAction() {
  // Object obj = "ws1";
  // print(obj.substring(1));//编译时报错
  dynamic obj1 = 123;
  print(obj1.substring(1)); //编译时不报错 运行时报错
}

class Perosn {
  String name = '';
  int age = 0;
  double height = 0;
  // 普通构造方法
  // Perosn(String name, int age) {
  //   this.age = age;
  //   this.name = name;
  // }
  //语法糖
  // Perosn(this.name, this.age);
  // Perosn(this.name, this.age,this.height);

  //命名构造方法
  Perosn.withNameAgeHeight(this.name, this.age, this.height);
  Perosn.fromMap(Map map) {
    this.name = map['name'];
    this.age = map['age'];
    this.height = map['height'];
  }
  //重写tostring方法
  @override
  String toString() {
    // TODO: implement toString
    return '$name $age $height';
    // return super.toString();
  }
}

  • 初始化列表

main(List args) {}

class Person {
  String name;
  //设置初始值方式1:
  int age;
  // int age = 10;
  //设置初始值方式2:初始化列表
  Person(this.name) : age = 10;
}

  • 重定向构造方法
main(List args) {
  var p = Person("ws");
  print('${p.age}  ${p.name}'); // 0  ws
}

class Person {
  String name;
  int age;
  //初始化列表
  // Person(this.name):age = 0;
  //构造函数的重定向
  Person(String name) : this._internal(name, 0);
  Person._internal(this.name, this.age);
}
  • 常量构造方法
/**
 * 常量构造方法
 * 在某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法.
 * ******这里我们使用identical(对象1, 对象2)函数来判断两个对象是否是同一个对象:
 * 
 * 如果将构造方法前加const进行修饰,那么可以保证同一个参数,创建出来的对象是相同的,这样的构造方法就称之为常量构造方法。
 * 
 * 常量构造方法有一些注意点:
 * 注意一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的.
 * 注意二: 为了可以通过常量构造方法,创建出相同的对象,不再使用 new关键字,而是使用const关键字
 * 注意三: 如果是将结果赋值给const修饰的标识符时,const可以省略.
 * 
 * 
 */
main(List args) {
  Dog p = Dog("xh");
  print('name is ${p.name} , age is ${p.age}'); //name is xh , age is 0

  var p1 = Person("ws");
  var p2 = Person("ws");
  print(identical(p1, p2)); //false

  var p3 = const Person("ws");
  var p4 = const Person("ws");
  print(identical(p3, p4)); //true

  const p5 = Person("ws");
  const p6 = Person("ws");
  print(identical(p5, p6)); //true

  final ws = Person("ws");
  final ws1 = Person("ws");
  print(identical(ws, ws1)); //false
}

class Dog {
  String name;
  int age;
  //初始化列表
  // Person(this.name) : age = 10;
  //重定向构造函数
  Dog(String name) : this.initWithData(name, 0);
  //命名构造函数
  Dog.initWithData(this.name, this.age);
}

class Person {
  final String name;
  const Person(this.name);
}
  • 工厂构造方法
/**
 * 普通的构造函数:会默认返回创建出来的对象 不需要写return返回值的
 * 工厂构造函数(factory):需要自己手动的返回一个我们的对象
 * 
 * 
 * 工厂构造函数最大的特点:就是可以手动的返回一个对象
 */

main(List args) {
  final s1 = Student("ws");
  final s2 = Student("Ws");
  print(identical(s1, s2)); //false

  final p1 = Person.withName("ws");
  final p2 = Person.withName("ws");
  final p3 = Person.withName("ws3");
  final p4 = Person.withName("ws3");
  print(identical(p1, p2)); //true
  print(identical(p2, p3)); //false
  print(identical(p3, p4)); //true
  print(identical(p1, p2)); //true

  /**
   * 为何使用final修饰对象 而不用var  因为这是命名规范,类似swift 使用let不用var  es6使用const
   * 不用let    就是防止创建的对象被恶意修改
   */
}

class Student {
  String name;
  Student(this.name);
}

class Person {
  String name;
  String color;
  static final Map _nameCache = {};
  static final Map _colorCache = {};

  factory Person.withName(String name) {
    if (_nameCache.containsKey(name)) {
      // return _nameCache[name];
      return _nameCache[name]!;
    } else {
      final p = Person(name, "default");
      _nameCache[name] = p;
      return p;
    }
  }

  factory Person.withColor(String color) {
    if (_colorCache.containsKey(color)) {
      // return _colorCache[color];
      return _colorCache[color]!;
    } else {
      final p = Person("default", color);
      _colorCache[color] = p;
      return p;
    }
  }
  //自定义构造函数
  Person(this.name, this.color);
}

3.类的setter和getter
main(List args) {
  final p = Person();
  //直接访问属性
  p.name = "ws";
  print(p.name); //ws
  print(p.getName); //ws
  //通过setter和getter来访问
  p.setName = "ws1";
  print(p.getName); //ws1
}

class Person {
  String name = "";
  //setter 标准写法
  set setName(String name) {
    this.name = name;
  }
  //setter的箭头函数写法
  // set setName(String name) => this.name = name;

  //getter 标准写法
  String get getName {
    return this.name;
  }
  //getter 箭头函数的写法
  // String get getName => this.name;
}

4.类的继承

Dart中的继承使用extends关键字,子类中使用super来访问父类。

/**
 * 1.父类中的所有成员变量和方法都会被继承,,但是构造方法除外。
 * 2.子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法)。
 * 3.如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super显式调用父类的某个构造方
 * 法。
 */
main(List args) {
  final p = Person("ws", 29);
  print(p.name); //ws
  print(p.age); //29
}

class Animal {
  int age;
  Animal(this.age);
  Animal.withDate(this.age);
}

class Person extends Animal {
  String name;
  Person(this.name, int age) : super(age);
}

5.抽象类

抽象类是使用abstract声明的类

/**
 * 抽象类
 * 所以在定义很多通用的**调用接口**时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。
 * 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。
 * 
 * 抽象方法:在Dart中没有具体实现的方法(没有方法体),就是抽象方法。
 * 1.抽象方法,必须存在于抽象类中。
 * 2.抽象类是使用abstract声明的类
 * 
 * 注意事项:
 * **注意一:**抽象类不能实例化.(不能通过普通的构造函数进行实例化,但是可以通过工厂构造函数进行实例化)
 * **注意二:**抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写.
 * 
 */
main(List args) {
  // 抽象类不能实例化.
  // final s = Shape();//报错
  //可以使用工厂构造函数实例化
  // final m = Map();
  // final s = Shape();
}

//抽象类
abstract class Shape {
  //只有方法的声明,没有方法的实现
  int ws_getAreaAction();
  //当然也可以有方法的实现
  String ws_getInfoAction() {
    return "形状";
  }

  //工厂构造函数
  // factory Shape() {
  //   // return Shape();//此行代码死循环
  // }
}

//继承于抽象类,必须实现抽象类中的抽象方法
class Rectangle extends Shape {
  @override
  int ws_getAreaAction() {
    return 100;
  }
}

//普通类
class Person {
  //普通类必须有方法的实现
  // void ws_runAction();//报错
}

6.隐式接口
/**
 * Dart中没有哪一个关键字是来定义接口的
 * 没有这些关键字interface/protocol
 * 默认情况下所有的类都是隐式接口
 * Dart只支持单继承
 * 当将一个类当做接口使用时,那么实现这个接口的类,必须实现这个接口中的所有方法
 */
main(List args) {
  final wm = woman();
  wm.ws_runAction(); //跑
  wm.ws_flyAction(); //飞
}

abstract class Runner {
  ws_runAction();
}

abstract class Flyer {
  ws_flyAction();
}

class woman implements Runner, Flyer {
  @override
  ws_runAction() {
    print('跑');
  }

  @override
  ws_flyAction() {
    print('飞');
  }
}

7.Mixin混入
/**
 * Dart中没有哪一个关键字是来定义接口的
 * 
 * 如果混入 父类 和 自己都有相同的方法  执行: 如果自己有就用自己的  自己没有就用混入的  混入没有才用父类的
 */
main(List args) {
  final sm = SuperMan();
  sm.ws_runAction(); //跑 //混入run
  sm.ws_flyAction(); //飞
}

mixin Runner {
  void ws_runAction() {
    print("跑");
  }
}

mixin Flyer {
  void ws_flyAction() {
    print("飞");
  }
}

class Animal {
  ws_eatAction() {
    print("吃");
  }

  void ws_runAction() {
    print("父类跑");
  }
}

class SuperMan extends Animal with Runner, Flyer {
  @override
  void ws_runAction() {
    super.ws_runAction();
    print("混入run");
  }
}

8.类属性和方法
main(List args) {
  var stu = Student();
  stu.name = 'ws';
  stu.sno = 99;
  stu.ws_studyAction();

  Student.time = '8点';
  // stu.time = '8点'; 错误做法, 实例对象不能访问类成员
  Student.ws_attendClassAction();
  // stu.ws_attendClassAction(); 错误做法, 实现对象不能访问类方法
}

class Student {
  //成员变量
  String name = "";
  int sno = 0;
  //静态属性(类属性)
  static String time = "";

  //对象方法
  ws_studyAction() {
    print('$name学习外语');
  }

  //静态方法(类方法)
  static ws_attendClassAction() {
    print('去上外语课');
  }
}

9.枚举类型

枚举也是一种特殊的类, 通常用于表示固定数量的常量值。枚举使用enum关键字来进行定义。

main(List args) {
  final color = Colors.pink;
  switch (color) {
    case Colors.red:
      print("red");
      break;
    case Colors.blue:
      print("blue");
      break;
    case Colors.green:
      print("green");
      break;
    case Colors.pink:
      print("pink");
      break;
    default:
      print('其他颜色');
  }
  print(Colors.values); //[Colors.red, Colors.blue, Colors.green, Colors.pink]
  print(Colors.red.index); //0
  print(Colors.pink.index); //3
}

enum Colors { red, blue, green, pink }

你可能感兴趣的:(三.Flutter之Dart语法(类和对象))