博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dart2笔记-类
阅读量:5811 次
发布时间:2019-06-18

本文共 10186 字,大约阅读时间需要 33 分钟。

基本概念

  • Object类:Dart是一个面向对象编程语言,每个对象都是一个类的实例,所有的类都继承于Object。
//定义一个类class Person {}复制代码
  • 类的继承性:每个类(Object 除外) 都只有一个超类(父类),一个类的代码可以被其他多个类继承来使用。
  • 创建新对象:使用new 关键字和构造函数来,构造函数名字可以类名;
  • 对象的成员:包括方法和数据 (函数和示例变量),使用点(.)来引用对象的变量或者方法,使用 ?. 来替代 . 来访问对象可以避免当左边对象为 null 时候抛出异常.
// If p is non-null, set its y value to 4.p?.y = 4;复制代码
  • 获取实例对象的类型:可以使用 Object 的 runtimeType 属性来判断实例的类型,该属性返回一个 Type对象。
class Student {}main() {  var a = new Student();  print(a.runtimeType); //Student}复制代码

类变量和函数

静态变量
  • 静态变量:static关键字修饰的类级别的变量,直接使用"类名.x"来调用;
  • 静态变量使用lowerCamelCase 来命名常量。
  • 静态变量在定义的时候可以不初始化,此时默认为null。
class Person {  static String name;  static const sex = "男";}main() {  print(Person.name);  print(Person.sex);}复制代码
静态函数

static 修饰的函数即静态函数,静态函数不再类实例上执行, 所以无法访问 this。

注意: 对于通用的或者经常使用的静态函数,考虑 使用顶级方法而不是静态函数。

class Person {  static void printInfo(){    print("hello world");  }}main() {  Person.printInfo();}复制代码

实例的私有属性

和Java不同的是,Dart没有public、protected、和private关键字。如果一个标识符以 (_) 开头,则该标识符在库内是私有的。

实例变量

  • 类的实例变量,所有没有初始化的变量值都是null。
  • 如果你在实例变量定义的时候初始化该变量(不是 在构造函数或者其他方法中初始化),改值是在实例创建的时候 初始化的,也就是在构造函数和初始化参数列 表执行之前。
  • 每个实例变量都会自动生成一个getter和setter方法(隐含的)。
class Person {  //类的实例变量  String name;  String sex;  int age;}main() {  var p = new Person();  p.age = 24; // Use the setter method for x.  print(p.age.toString());}复制代码

this关键字

this 关键字指当前的实例,只有当名字冲突的时候才使用 this,Dart代码风格样式推荐忽略 this

class Point {  num x;  num y;  Point(num x, num y) {    // There's a better way to do this, stay tuned.    this.x = x;    this.y = y;  }}复制代码

构造函数赋值实例变量简化写法:

class Point {  num x;  num y;  //由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作:  // Syntactic sugar for setting x and y  // before the constructor body runs.  Point(this.x, this.y);}复制代码

函数

函数是类中定义的方法,是类对象的行为。

实例函数

实例函数是类中定义的普通方法,类实例对象可以调用的方法,对象的实例函数可以访问this;

class Person {  String name;  printName() {    print(this.name);  }}main() {  new Person()    ..name = 'ethan'    ..printName();}复制代码
getter and setter

getter 和 setter 是用来设置和访问对象属性的特殊函数,定义时需要在变量名前加get或set标识。

特点:

  • 每个实例变量默认隐含一个getter,如果变量不是final类型,则还会隐含一个 setter。
  • 可以通过getter 和 setter 来创建新的属性,使用 get 和 set 关键字定义 getter和setter;
  • 如果定义一个带get标识的变量,则实例对象可以直接通过“对象.x”来获取变量,但是这个变量没有setter,此时必须也实现setter,才可以通过“对象.x=n”来改变此变量;
class Person {  String name;  String prefix;  Person(this.name);  String get description => prefix + " " + name;  set description(String prefix) => this.prefix = prefix;}main() {  var p = new Person("ethan");  p.description = 'x';  print(p.description);}复制代码
抽象函数

抽象函数是没有函数体的函数。

实例函数、 getter、和 setter 函数可以为抽象函数, 抽象函数是只定义函数接口但是没有实现的函数,由子类来 实现该函数。

示例:

//抽象类abstract class Doer {  //抽象方法  void doSomething();}//子类继承抽象类,必须实现抽象方法class EffectiveDoer extends Doer {  void doSomething() {    print("hello");  }}复制代码

构造函数

概述

定义一个和类名字一样的方法就定义了一个构造函数。 构造函数用来生成一个对象的新实例;

  • 默认构造函数:与类同名,配合new关键字创建实例。如果没有定义构造函数,则会有个默认构造函数。 默认构造函数没有参数,并且会调用超类的 没有参数的构造函数。
  • 构造函数不会继承:子类不会继承超类的构造函数。 子类如果没有定义构造函数,则只有一个默认构造函数 (没有名字没有参数)。
  • 命名构造函数:定义格式为“类名.函数名(...)”,创建对象实例时也使用“类名.函数名(...)”.使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图;
class Person {  //类的实例变量  String name;  int age;  //默认构造函数  Person();  // Person(this.name, this.age);  //命名构造函数  Person.fromJson(Map jsonMap) {    name = jsonMap['name'];    age = jsonMap['age'];  }}main() {  var p = Person.fromJson({
'name': "ethan", "age": 11}); print(p.name); print(p.age);}复制代码
调用超类构造函数
默认调用方式

子类的构造函数会自动调用超类的 无名无参数的默认构造函数。 超类的构造函数在子类构造函数体开始执行的位置调用。 如果提供了一个 initializer list(初始化参数列表) ,则初始化参数列表在超类构造函数执行之前执行。

下面是构造函数执行顺序:

1. initializer list(初始化参数列表)2. superclass’s no-arg constructor(超类的无名构造函数)3. main class’s no-arg constructor(主类的无名构造函数)复制代码
超类是无参数构造函数

如果超类没有无名无参数构造函数, 则你需要手工的调用超类的其他构造函数。 在构造函数参数后使用冒号 (:) + () 可以调用 超类构造函数。

class Person {  String firstName;  Person.fromJson(Map data) {    print('in Person');  }}class Employee extends Person {  // Person does not have a default constructor;  // you must call super.fromJson(data).  Employee.fromJson(Map data) : super.fromJson(data) {    print('in Employee');  }}main() {  var emp = new Employee.fromJson({});    //in Person    //in Employee}复制代码

注意:

  • 如果在构造函数的初始化列表中使用 super(),需要把它放到最后。
  • 调用超类构造函数的参数无法访问 this。 例如,参数可以为静态函数但是不能是实例函数。
构造函数初始化列表

在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。 使用逗号分隔初始化表达式。

警告: 初始化表达式等号右边的部分不能访问 this。

class Point {  num x;  num y;  Point(this.x, this.y);  // Initializer list sets instance variables before  // the constructor body runs.  Point.fromJson(Map jsonMap)      : x = jsonMap['x'],        y = jsonMap['y'] {    print('In Point.fromJson(): ($x, $y)');  }}复制代码
重定向构造函数

有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。

class Point {  num x;  num y;  // The main constructor for this class.  Point(this.x, this.y);  // Delegates to the main constructor.  Point.alongXAxis(num x) : this(x, 0);}复制代码
常量构造函数

如果你的类提供一个状态不变的对象,你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const 构造函数, 并且声明所有类的变量为 final。

  • 使用常量构造函数 可以创建编译时常量,要使用常量构造函数只需要用const替代new 即可;
  • 两个使用常量构造函数创建,并且创建时的内容一样常量对象,其实是同一个对象;
class ImmutablePoint {  final num x;  final num y;  const ImmutablePoint(this.x, this.y);  static final ImmutablePoint origin =      const ImmutablePoint(0, 0);}var a = const ImmutablePoint(1, 1);var b = const ImmutablePoint(1, 1);assert(identical(a, b)); // They are the same instance!复制代码
工厂方法构造函数

如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。

工厂构造函数无法访问 this。

示例:定义工厂构造函数。

class Logger {  final String name;  bool flag = false;  //_cache: 静态私有变量缓存实例对象  static final Map
_cache =
{}; factory Logger(String name) { if (_cache.containsKey(name)) { //获取缓存 return _cache[name]; } else { //缓存 final logger = new Logger._internal(name); _cache[name] = logger; return logger; } } //命名构造函数 Logger._internal(this.name); //改变flag的值 void changeFlag() { flag = !flag; }}main() { var logger = new Logger('LOG'); print("flag = " + logger.flag.toString()); logger.changeFlag(); //缓存的logger对象 print("flag = " + new Logger('LOG').flag.toString()); //新的logger对象 print("flag = " + new Logger('X').flag.toString());}复制代码
//执行结果:flag = falseflag = trueflag = false复制代码

可覆写的操作符

下表中的操作符可以被覆写:

<	+	|	[]>	/	^	[]=<=	~/	&	~>=	*	<<	==–	%	>>	 复制代码
覆写示例
对象加减

覆写+-法:

class Vector {  final int x;  final int y;  const Vector(this.x, this.y);  /// Overrides + (a + b).  Vector operator +(Vector v) {    return new Vector(x + v.x, y + v.y);  }  /// Overrides - (a - b).  Vector operator -(Vector v) {    return new Vector(x - v.x, y - v.y);  }}main() {  final v = new Vector(2, 3);  final w = new Vector(2, 2);  // v == (2, 3)  assert(v.x == 2 && v.y == 3);  // v + w == (4, 5)  assert((v + w).x == 4 && (v + w).y == 5);  // v - w == (0, 1)  assert((v - w).x == 0 && (v - w).y == 1);}复制代码
覆写==

Dart 中的每个对象都有一个整数 hash 码,这样每个对象都 可以当做 map 的 key 来用。但是,你可以覆写 hashCode getter 来自定义 hash 码的实现,如果你这样做了,你也需要 同时覆写 == 操作符。相等的对象(使用 == 比较)的 hash 码应该一样。hash code 码并不要求是唯一的, 但是应该具有良好的分布形态。

如果你覆写了 == ,则还应该覆写对象的 hashCode getter 函数。

class Person {  final String firstName, lastName;  Person(this.firstName, this.lastName);  // Override hashCode using strategy from Effective Java,  // Chapter 11.  int get hashCode {    int result = 17;    result = 37 * result + firstName.hashCode;    result = 37 * result + lastName.hashCode;    return result;  }  // You should generally implement operator == if you  // override hashCode.  bool operator ==(other) {    if (other is! Person) return false;    Person person = other;    return (person.firstName == firstName &&        person.lastName == lastName);  }}main() {  var p1 = new Person('bob', 'smith');  var p2 = new Person('bob', 'smith');  var p3 = 'not a person';  assert(p1.hashCode == p2.hashCode);  assert(p1 == p2);  assert(p1 != p3);}复制代码

抽象类

使用“abstract”关键字修饰的类为抽象类,不能实例化,抽象类的方法可以实现也可以不实现;

  • 如果你希望你的抽象类 是可示例化的,则定义一个 工厂构造函数。
  • 抽象方法即没有方法体的方法,普通类不能有抽象方法;
//抽象类abstract class Person {  void eat();}//子类实现抽象类的方法class Student extends Person {  void eat(){    print("i can eat");  }}main() {  new Student().eat();}复制代码

类的隐式接口

  • 每个类都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。
  • 一个类可以通过 implements 关键字来实现一个或者多个接口, 并实现每个接口定义的 API。

如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。例如:

class Person {  final _name;  Person(this._name);  String greet(who) => 'hello, $who. I am $_name.';}class Animal {  void eat() {}}//实现多个接口class StudentImpl implements Person, Animal {  final _name = "";  String greet(who) => 'Hi $who. Do you know who I am?';  void eat() {    print("i can eat");  }}greetBob(Person person) => person.greet('bob');main() {  print(greetBob(new Person('kathy')));  print(greetBob(new StudentImpl()));}复制代码

类继承

  • 子类通过extends来继承父类;
  • 通过super来调用父类方法;
  • 可以使用 @override注解一个函数,来表明你的函数是想覆写超类的一个函数;

继承示例如下:

class Animal {  void eat() {    print("i can eat");  }  void greet() {    print("hello everyone !");  }}class Person extends Animal {  void printFeature() {    super.eat();  }  //重写父类函数  @override  void greet() {    print("hello i am person");  }}main() {  new Person().greet();}复制代码

枚举类型

枚举类型通常称之为 enumerations 或者 enums, 是一种特殊的类,用来表现一个固定 数目的常量。

  • 使用 enum 关键字来定义枚举类型;
  • 枚举类型中的每个值都有一个 index getter 函数, 该函数返回该值在枚举类型定义中的位置(从 0 开始)。
  • 枚举的 values 常量可以返回 所有的枚举值。
  • 可以在 switch 语句 中使用枚举。 如果在 switch (e) 中的 e 的类型为枚举类, 如果你没有处理所有该枚举类型的值的话,则会抛出一个警告;
  • 枚举类无法继承枚举类型、无法使用 mix in、无法实现一个枚举类型;
  • 枚举类无法显示的初始化一个枚举类型;
enum Color { red, green, blue }judgeType(Color color) {  switch (color) {    case Color.blue:      print("yes i am blue");      break;    default:      print("no");      break;  }}main() {  print(Color.green.index); // 1  print(Color.values); //枚举值列表[Color.red, Color.green, Color.blue]  //枚举应用switch  judgeType(Color.red);  judgeType(Color.blue);}复制代码

mixins重用类

mixins可以实现类似继承多个类功能的效果,重用多个类的属性。

  • mixins使用with关键字后跟需要的类;
  • Dart 1.13之前,定义一个类继承Object,该类没有构造函数,不能调用 super ,则该类就是一个 mixin。
  • Dart 1.13+,mixins可以继承其他类,不再限制为继承Object,可以调用 super()。

super mixins” 还 无法在 dart2js 中使用 并且需要在 dartanalyzer 中使用 --supermixin 参数。

class Animal {  final name = "ethan";}class Musical {  void printFeature() {    print("i can song");  }}class Person {  String iq;}class Student extends Person with Animal, Musical {  void printInfo() {    print("name=" + name);    super.printFeature();    printFeature();    super.iq = "100";    print("IQ=" + iq);  }}main() {  new Student().printInfo();}复制代码

转载于:https://juejin.im/post/5c3ef7ebf265da6179750fb1

你可能感兴趣的文章
聊一聊log4j2配置文件log4j2.xml
查看>>
NeHe OpenGL教程 第七课:光照和键盘
查看>>
修改上一篇文章的node.js代码,支持默认页及支持中文
查看>>
Php实现版本比较接口
查看>>
删除设备和驱动器中软件图标
查看>>
第四章 TCP粘包/拆包问题的解决之道---4.1---
查看>>
html语言
查看>>
从源码看集合ArrayList
查看>>
spring-boot支持websocket
查看>>
菜鸟笔记(一) - Java常见的乱码问题
查看>>
我理想中的前端工作流
查看>>
记一次Git异常操作:将多个repository合并到同一repository的同一分支
查看>>
CodeIgniter 3.0 新手捣鼓源码(一) base_url()
查看>>
Chrome 广告屏蔽功能不影响浏览器性能
查看>>
vSphere 6将于2月2日全球同步发表
查看>>
Android状态栏实现沉浸式模式
查看>>
让你的APP实现即时聊天功能
查看>>
iOS 绝对路径和相对路径
查看>>
使用Openfiler搭建ISCSI网络存储
查看>>
应用新安全组 - 每天5分钟玩转 OpenStack(116)
查看>>