Flutter-Dart语法二

面向对象特性

1.类(class )

Dart是一个面向对象编程语言,同时支持基于mixin的继承机制。每个对象都是一个类的实例,所有的类都继承于object。

1)构造函数
构造函数不能继承。父类的命名构造函数也不会被继承,如果子类也有父类一样命名构造函数,就必须在子类中自己实现该构造函数。

  • 默认构造函数:如果未显式定义构造函数,会默认一个参数为空的构造函数。默认构造函数会调用父类的无参构造函数。
class  Person { //未定义父类的时候,默认继承自Object
  num x;
  num y;
  num z;
}

void main(List args){
  var person = new Person();//调用默认的构造函数
  person.x = 10;   //使用点(.)引用实例变量或方法
  person.y = 11;
}
  • 类名构造函数:就是一个与类同名的函数,关键字 this 是指当前实例,只有在命名冲突时有效,否则dart会忽略处理。

class Point {
    int x;
    int y;
  //自己定义的类名构造函数
  Point(int x, int y) {
      this.x = x;
    this.y = y;
   }
   
   // 在构造函数里初始化成员属性是很常见的事情,因此Dart开发了新的语法糖来简化这种操作
   // 比如将Point的类名构造构造函数改写成

   // Point(this.x, this.y);
  // 注意x,y的赋值会在构造函数执行之前完成.
   
}
void main(){
    var point = new Point(1, 2);
}

  • 命名构造函数:(类名.函数名)使用命名构造函数可以为类提供多个构造函数。
class Point {
  num x, y;

  Point(this.x, this.y);

  // 命名构造函数
  Point.origin() {
    x = 0;
    y = 0;
  }
  // 简化
  // Point.origin(this.x,this.y);
  
}

  • 重定向构造函数:有时构造函数的唯一目的是重定向到同一类中的另一个构造函数。重定向构造函数的主体为空,构造函数调用出现在冒号( :)之后 。
    大意就是在创建类时,我定义一个命名构造函数,但是这个构造函式的主体我不实现。直接通过:调用另外一个构造函数,实现对外界传入的参数的接收并赋值给内部的变量。
class Point {
  num x, y;
  //类名构造函数
  Point(this.x, this.y);
  // 命名构造函数
 Point.order(this.x,this.y);
 Point.origin(num a,num b):this.order(a,b);  
 //重定向构造函数,origin构造函数将外界的传值,指向给了order构造函数。
}

  • 工厂构造函数:在实现一个构造函数时使用factory关键字,该构造函数并不总是创建其类的新实例。例如,工厂构造函数可能会从缓存中返回实例,也可能会返回子类型的实例。工厂构造者对this没有访问权限。
class Logger {
  final String name;
  bool mute = false;

 // _cache是私有变量
 //_在名称前,表示该变量为私有
  static final Map _cache = {};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
     } else {
       final logger = Logger._internal(name);
       _cache[name] = logger;
       return logger;
    }
  }

  Logger._internal(this.name);
  void log(String msg) {
    if (!mute) print(msg);
   }
}


调用:
var logger = Logger('UI');
logger.log('Button clicked');

  • 常量构造函数:如果你的类创建的对象从不改变,你可以创建一些编译时的常量对象。因此,定义一个const构造函数,且保证所有的对象变量都是final。
class ImmutablePoint {
  final num x;
  final num y;
  const ImmutablePoint(this.x, this.y);
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);
}

注意:如果父类中没有默认的构造函数,你必须手动调用父类的构造函数,在子类的构造函数体之前通过(:) 指定调用父类构造函数,示例如下:

// Person类中没有一个无参数,未命名的构造函数
class Person {
  String firstName;
  // 命名构造函数
  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // 你必须调用父类的super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});
}


2.实例变量

声明实例变量时,所有未初始化的实例变量的值为null。
每个实例变量都会自动生成一个getter方法,Non-final(没有被final修饰)实例变量还会自定生成一个setter方法。

class Point{
  num x;//声明实例变量x,初始化为空
  num y;//声明实例变量y,舒适化为空
  num z = 0;//声明实例变量z,初始化为0
  //如果在实例变量定义的时候初始化该变量(不是在构造函数或者其他方法中初始化),该值是在实例化对象的时
  //候初始化的,也就是在构造函数和初始化参数列表执行之前。
  
}
void main() {
  var point = new Point();
  point.x = 4;              //使用setter方法对x变量赋值
  print(point.x == 4);      //输出true 使用getter获取x变量的值
  print(point.y == null);   //输出true

}

静态(类)变量:使用static关键字来实现类级别的变量和方法,静态函数内部不能访问非静态成员,非静态函数能访问静态成员。

class Queue {
  // 静态变量在使用之前不会初始化
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

3.方法

1)实例方法
对象的实例函数可以访问this。
import 'dart:math';

class Point {
  num x;
  num y;
  Point(this.x, this.y);

  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

2)类方法
使用static 修饰的方法,内部不能访问实例变量,没有访问this的权限。

class Page{
  // 添加 static 关键字
  static int currentPage = 1;
  num size ;
  
  //类方法
  static void scorllDown(){
    currentPage = 1;
    // 访问实例变量报错
    // size = 10;
    print("ScrollDown...");
  }
 
  void scorllUp(){
    currentPage ++;
    print("ScrollUp...");
  }
}

void main(List args) {
  var page = new Page();
  // 调用类方法
  Page.scorllDown();
}


3)Getters和Setters 方法
Getters 和setters是用来设置和访问对象属性的特殊函数。每个实例变量都隐含的具有一个getter,如果变量不是final的则还有一个setter。使用get和set关键字定义getter和setter。

class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  // 定义两个计算属性:右和下。
  num get right             => left + width;
      set right(num value)  => left = value - width;
  num get bottom            => top + height;
      set bottom(num value) => top = value - height;
}

main() {
  var rect = new Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

4)抽象函数

抽象函数是只定义函数接口但是没有实现的函数,由子类来实现该函数。如果用分号来替代函数体则这个函数就是抽象函数。

abstract class Doer {
  // ...定义实例变量和方法...

  void doSomething(); // 定义一个抽象方法.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // ...提供实现,因此此处的方法不是抽象的...
  }
}

4.抽象类

使用abstract修饰符定义一个抽象类,一个不能被实例化的类。抽象类通常用来定义接口,如果你想实例化抽象类,你必须实现抽象类,才能被实例化。

// 这个类是抽象类,不能实例化
abstract class AbstractContainer {
  // ...定义构造函数, 变量, 方法...

  void updateChildren(); // 抽象方法.
}

class SpecializedContainer extends AbstractContainer {
  // ...定义更多的构造方法, 方法...

  void updateChildren() {
    // ...实现 updateChildren()...
  }

}


5.隐式接口

Dart中没有哪个关键字是来定义接口的, 默认情况下所有的类类都是都是隐式的接口,包括类的方法和属性。当将一个类当做接口使用时,那么实现这个接口的类,必须实现这个接口中所有的方法。

// A person. 隐式接口包含greet().
class Person {
  // 在接口中,但仅在此库中可见
  final _name;

  // 不在接口中,因为这是构造函数
  Person(this._name);

  // 在接口中
  String greet(who) => 'Hello, $who. I am $_name.';
}

// 实现Person 接口
class Imposter implements Person {
  // 我们必须定义这个,但我们不使用它。
  final _name = "";

  String greet(who) => 'Hi $who. Do you know who I am?';
}

6.类的继承

使用extends创建子类,super引用父类,子类可以重写实例方法、getter和setter,使用@override注释重写,使用@proxy注释来忽略警告

class Person {
  
 void run{
     print('people run');
 }
 
}

class Kids{
    @override
    void run{
     print('Kids run');
 }
}



重写object的noSuchMethod()
当用户调用你定义的类中不存在的属性与方法时,通过重写noSuchMethod(),可以做出一些响应。
class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}


7.访问控制

默认类中的所有属性和方法是public的。在dart中,可以在属性和方法名前添加“_”使私有化。

class Animal{
  String _name;   // 私有属性
  int age; 
  //默认构造函数的简写
  Animal(this._name,this.age);

  void printInfo(){   
    print("${this._name}----${this.age}");
  }

// 供外部调用私有属性
  String getName(){ 
    return this._name;
  } 
  // 私有方法
  void _run(){
    print('这是一个私有方法');
  }

  execRun(){
    this._run();  //类里面方法的相互调用
  }
}


void main(){
 
 Animal a=new Animal('小狗', 3);

 print(a.getName());

  a.execRun();   //间接的调用私有方法

}

8.枚举类型

枚举中的每个值都有一个index索引,它返回枚举声明中值的从零开始的位置。例如,第一个值具有索引0,第二个值具有索引1。

enum Color { red, green, blue }

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

可以在switch语句中使用枚举,如果不处理枚举的所有值,将会收到警告。

9.泛型

泛型就是定义的一个类型,类型暂不确定,给使用给一个占位符给代替,在使用的时候可以给确定其定义的类型。

main() {
// 如果自己希望List只包含字符串对象。则可以定义为List代表("list of string")。

   List Tech = new List();
   Tech.addAll(['Android','IOS','Flutter']);
   Tech.add(42);//运行时报错
}

你可能感兴趣的:(Flutter-Dart语法二)