zoukankan      html  css  js  c++  java
  • Dart入门(三)类、泛型、异常处理

    Dart语言——45分钟快速入门(下)

    Dart语法学习

    Dart学习笔记(五):类

     

    一、类

    1、定义一个类

    class Person {
      String name;
      int age;
    
      Person(String name, int age) {
        this.name = name;
        this.age = age;
      }
    }

    简化后可写成

    class  Person {
        String name;
        int age;
    
        // 在构造方法中初始化成员变量时,可使用如下写法简化
        Person(this.name, this.age);
    }

    如需处理其他变量时,也可单独对其操作

    class  Person {
        String name;
        int age;
    // 如需处理其他变量时,也可单独对其操作 Person(this.name, this.age, String address){ print(address); } }

    2、Getters 和 Setters方法

    所有类中都包含隐式的getter方法,对于非final修饰的成员,类中还包含隐式的setter方法。

    很多时候我们调用setter和getter方法并不仅仅是为了赋值和访问,而是为了一些额外的处理

    class  Person {
        String userName;
    
        Person(this.userName);
    
        // 方法名前加get关键字
        String get name{
            return  "user:"  +  this.userName;
        }
    
        // 方法名前加set关键字
        set name(String name){
            // do something
            this.userName = name;
        }
    }

    可以通过实现 getters 和 setters 来创建附加属性,也就是直接使用 get 和 set 关键词:

    class Rectangle {
       num left;
       num top;
       num width;
       num height;
    
       Rectangle(this.left, this.top, this.width, this.height);
    
       // 定义两个计算属性: right and bottom.
       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);
    }

    3、命名构造方法

    不支持构造方法重载,但有命名构造方法

    class  Person {
        String userName;
        int age;
    
        Person(this.userName, this.age);
    
        // 命名构造方法
        Person.fromData(Map data) {
            this.userName = data['name'];
            this.age = data['age'];
        }
    }
    
    void  main() {
        // 使用命名构造方法创建对象
        var p = new Person.fromData({
            "name":"Bob",
            "age":19
        });
        print(p.userName);
    }

    Dart的构造函数

    子类只能继承父类无名、无参数的构造函数(即子类不会继承父类的无名有参构造函数和命名构造函数)

    默认情况下,子类只能调用父类的无名、无参数的构造函数,

    如果父类不显示提供无名无参的构造函数,在子类中必须手动调用父类的一个构造函数(这里应该是这父类的一个有名构造函数)

    lyh总结:子类构造函数需要手动调用父类的一个构造函数(若父类有一个显示的无名无参构造函数,子类可不用手动调父类的构造函数(默认调显示的无名无无参构造函数了)。) 

    4、常量构造函数

    如果想提供一个状态永远不变的对像,在Dart中,我们可以创建一个编译时常量对象,节省开销。

    如果类提供的是状态不变的对象,那么可以把这些对象定义为编译时常量,实现这种功能可以定义const构造函数,且声明所有类的变量为final,如:

    class ConstPoint {
      final num x;
      final num y;
    
      // 使用const修构造方法
      const ConstPoint(this.x, this.y);
    
      // 编译时常量对象,需使用const来创建对象
    
      // 常量如果是类级别的,请使用 static
    
      static final ConstPoint origin = const ConstPoint(0, 0);
    
    }
    
    void main() {
      print(ConstPoint.origin.x);
      print(ConstPoint.origin.y);
    }

    5、静态方法、静态常量

    static 关键字来实现类级别变量和函数、类中的常量需要使用static const声明

    静态成员不能访问非静态成员、非静态成员可以访问静态成员

    class People{
      static int age;
      static void Say(){
        print('hello!');
      }
    }
    
    void main(){
      People.age = 10;
      People.Say();
    }

    6、工厂构造方法

    当我们需要创建一个新的对象或者从缓存中取一个对象时,工厂构造方法就派上了用场。

    注意:工厂构造函数不能用 this。

    class  Logger {
        final String name;
    
        // 创建一个静态Map做为缓存,
        static final Map<String, Logger> _cache =  <String, Logger>{};
    
        // 定义一个命名构造方法,用下划线"_"修饰,将构造方法私有化
        Logger._internal(this.name);
    
        // 使用关键字factory修饰类同名构造方法
        factory Logger(String name) {
            if (_cache.containsKey(name)) {
                return _cache[name];
            } else {
                // 调用命名构造方法创建新对象
                final logger= new  Logger._internal(name);
                _cache[name] = logger; // 存入缓存
                return logger;
            }
        }
    }
    
    void  main() {
        var uiLog = new Logger('UI');
        var eventLog = new Logger('event');
    }

    7、构造方法重定向

    有时候一个构造方法会调动类中的其他构造方法来实例化,这时候可以使用构造方法重定向,

    class Point {
      num x;
      num y;
    
      // 同名构造方法
      Point(this.x, this.y);
    
      // 命名构造方法重定向到同名构造方法,中间使用一个冒号
      Point.alongXAxis(num x) : this(x, 0);
    }

    8、类的初始化列表

    位于构造方法的小括号与大括号之间,在初始化列表之前需添加一个冒号

    逗号分隔的一些赋值语句组成

    适合用来初始化 final修饰的变量

    调用是在构造方法之前

    class  Point {
        final  num x;
        final  num y;
        final  num distance;
    
        Point(x, y)
            : x = x,
              y = y,
              distance =  sqrt(x * x + y * y){
                 print("这是构造方法");
              }
    }
    
    void  main() {
        var p =  new  Point(2, 3);
        print(p.distance);
    }

    9、运算符重写

    class Point {
      int x;
      int y;
    
      Point(this.x, this.y);
    
      // 使用operator关键字,为该类重载"+"运算符
      Point operator +(Point p) {
        return new Point(this.x + p.x, this.y + p.y);
      }
    
      // 为该类重载"-"运算符
      Point operator -(Point p) {
        return new Point(this.x - p.x, this.y - p.y);
      }
    }
    
    void main(){
       var p1 = new Point(1,5);
       var p2 = new Point(7,10);
    
       // 重载运算符后,类可以使用“+”、“-” 运算符操作
       var p3 = p1 + p2;
       var p4 = p2 - p1;
    
       print("${p3.x}, ${p3.y}");
       print("${p4.x}, ${p4.y}");
    }

    10、类的单继承

    class Father {
        myFunction(){
            // do something
        }
    }
    
    class Son extends Father {
    
        @override
        myFunction(){
            super.myFunction();
            // do something
        }
    }

    11、mixin 混入

    当我们的继承父类不是同一个的,同时子类里面需要实现同样的功能时,Mixin显得尤为重要。

    理解Dart的Mixin继承机制

    Dart | 什么是Mixin

    demo1:

    abstract class Animal {}
    
    abstract class Mammal extends Animal {}
    
    abstract class Bird extends Animal {}
    
    abstract class Fish extends Animal {}
    
    abstract class Walker {
      // This class is intended to be used as a mixin, and should not be
      // extended directly.
      factory Walker._() => null;
    
      void walk() {
        print("I'm walking");
      }
    }
    
    abstract class Swimmer {
      // This class is intended to be used as a mixin, and should not be
      // extended directly.
      factory Swimmer._() => null;
    
      void swim() {
        print("I'm swimming");
      }
    }
    
    abstract class Flyer {
      // This class is intended to be used as a mixin, and should not be
      // extended directly.
      factory Flyer._() => null;
    
      void fly() {
        print("I'm flying");
      }
    }
    
    class Dolphin extends Mammal with Swimmer {}
    
    class Bat extends Mammal with Walker, Flyer {}
    
    class Cat extends Mammal with Walker {}
    
    class Dove extends Bird with Walker, Flyer {}
    
    class Duck extends Bird with Walker, Swimmer, Flyer {}
    
    class Shark extends Fish with Swimmer {}
    
    class FlyingFish extends Fish with Swimmer, Flyer {}

    demo2:

    class Father1 {
        a(){
          print("this is a func");
        }
    
        common(){
            print("common Father1");
        }
    }
    
    class Father2 {
        b(){
          print("this is b func");
        }
    
        common(){
            print("common Father2");
        }
    }
    
    class Father3 {
        c(){
          print("this is c func");
        }
    
        common(){
            print("common Father3");
        }
    }
    
    //定义子类
    class Son extends Father1 with Father2,Father3{
    
    }
    
    void main() {
      var obj = new Son();
      obj.common();
      obj.a();
      obj.b();
      obj.c();
    }

    打印结果

    common Father3
    this is a func
    this is b func
    this is c func

    以上写法中,也可以直接使用with,等价于如下写法

    class Son with Father1,Father2,Father3{
    
    }

    ps:

    1、另外还需要注意一点,Dart中没有构造方法的重载,不能写两个同名的构造方法。

    2、子类会继承父类显示的的无名无参的构造函数,父类中有命名构造函数,子类要手动继承。

    3、@override (重写)

    父类中有方法func(),子类会继承,子类想重写func(),会自动加上@override标记,且在方法中会自动加上super.func(); 

    如果删掉super.func(),则父亲类中的func()不会被调用,

    另外,子类中没实现func(),则子类调用func(),父类func()会被调用。

    4、默认情况下,子类只能调用父类的无名,无参数的构造函数; 父类的无名构造函数会在子类的构造函数前调用; 如果initializer list 也同时定义了,则会先执行initializer list 中的内容,然后在执行父类的无名无参数构造函数,最后调用子类自己的无名无参数构造函数。即下面的顺序:
    • initializer list(初始化列表)
    • super class’s no-arg constructor(父类无参数构造函数)
    • main class’s no-arg constructor (主类无参数构造函数)

    对于final变量的值,可以在初始化列表中指定

    class Person {
       String firstName;
    
       Person.fromJson(Map data) {
           print('in Person');
       }
    }
    
    class Employee extends Person {
       // 父类没有无参数的非命名构造函数,必须手动调用一个构造函数     
       Employee.fromJson(Map data) : super.fromJson(data) {
          print('in Employee');
       }
    }
    
    main() {
       var emp = new Employee.fromJson({});
    
       // Prints:
       // in Person
       // in Employee
       if (emp is Person) {
         // Type check
         emp.firstName = 'Bob';
       }
       (emp as Person).firstName = 'Bob';
    }

    二、抽象类 

    Dart语言没有提供interface关键字来定义接口,

    但是Dart语言中保留了抽象类,同Java,使用abstract关键字来修饰抽象类。而Dart中的抽象类,实际上就相当于Java中的接口。

    抽象类是不能被实例化的,子类继承抽象类时,必须实现全部抽象方法。

    如果你想让你的抽象类被实例化,请定义一个 工厂构造函数 。

    abstract class Base {
        // 省略函数体即可定义抽象方法,不需加关键字
        func1();
        func2();
    }

    三、隐式接口

    实际上在Dart中,每个类都隐式的定义了一个包含所有实例成员的接口, 并且该类实现了这个接口

     因此,如果我们想实现某个接口,但有又不想继承,则可以使用这种隐式接口机制。我们需要用到关键字implements

    class People {
      void greet(){
        print("Hello");
      }
    }
    
    class Student implements People{
      @override
      void greet(){
        print("Hi,I'm Alice.");
      }
    }
    
    greet(People p){
      p.greet();
    }
    
    void main() {
      greet(new Student());
    }

    接口是可以多实现的,如下:

    class TonyStart implements American, Scientist, Richman, Playboy {
        // ...
    }

    四、泛型

    var names = new List<String>();
    names.add("zhangsan")
    
    var maps = new Map<int, String>();
    maps[1]="value";

    字面量写法

    var infos = <String>['Seth', 'Kathy', 'Lars'];
    
    var pages = <String, String>{
      'index.html': 'Homepage',
      'robots.txt': 'Hints for web robots'
    };

    五、异常处理

      try {
          // 使除数为0
          print(11~/0);
      } on IntegerDivisionByZeroException {
          print("除数为0");
      }on Exception{
          print("Exception");
      }finally {
          print("finally");
      }

    不关心具体异常,只想捕获,避免异常继续传递

      try {
          print(11~/0);
      } catch(e){
          // 打印报错信息
          print(e);
      }finally {
          print("finally");
      }

    如果想获取更多异常信息,可以使用两个参数的catch,第二个参数是异常的调用栈信息

      try {
          print(11~/0);
      } catch(e,s){
          print(s);
      }

    如果你既想针对不同异常进行不同处理,还想打印调用栈信息,那就将两种结合起来使用

      try {
          print(11~/0);
      } on IntegerDivisionByZeroException catch(e,s){
          print(s);
      } on Exception catch(e,s){
          print(s);
      }
    
    
    
    
    
    
    
  • 相关阅读:
    warmup_csaw_2016
    pwn-简单栈溢出
    吃土
    编程中的进制转换
    linux系统安全及应用——账号安全(基本安全措施)
    vmware vSphere虚拟网络之标准交换机(二)
    vmware vSphere虚拟网络(一)
    服务器虚拟化技术概述
    用shell脚本安装apache
    The server of Apache (二)——apache服务客户端验证
  • 原文地址:https://www.cnblogs.com/liyonghua/p/11910773.html
Copyright © 2011-2022 走看看