Dart -- 较Java新特性(三)

作者:opLW
目的:在阅读Dart概览后进行的总结,主要记录Dart相比Java的新特性,包括许多亲自实验后的总结。如有错误还望指正😄
其他文章:
Dart – 较Java新特性(一)
Dart – 较Java新特性(二)

目录

8.异常
9.类

8.异常
  • 8.1 概述
    • 与Java不同Dart中没有必检异常和非必检异常之分,Dart中只有非必检异常。
    1. 即Dart不要求在一个方法中声明抛出异常(即没有和Java一样的关键字throws)
    2. Dart不会要求必须使用try..catch结构捕获异常。
    • Dart除了抛出传统的异常类ExceptionError外,还可以抛出不为任何不为null的对象。
      void main() {
        throw "I am a String";
      }
      // 抛出异常:Uncaught Error: I am a String
      
  • 8.2 throwJava类似用于抛出一个异常。
  • 8.3 catch
    • on、catch 与Java不同Dart将声明异常类型的部分分离出来,用on关键字声明,用catch关键字捕获异常。
      try {
        // 发生异常的代码
      } on Exception catch (e) {
        // 用on声明异常的类型
        print('Unknown exception: $e');
      } catch (e) {
        // 没有用on声明异常类型,所以对于任何异常都能处理
        print('Something really unknown: $e');
      }
      
    • catch块可以指定两个参数:第一个为e,代表异常;第二个为s,代表StackTrace异常的栈信息。
      try {
         throw "null null";
      } catch(e, s) {
         print("$s");
      }
      
      // 同时如果你不喜欢e和s,也可以换成别的关键字如:
      try {
         throw "null null";
      } catch(a, b) {
         print("$b");
      }
      
    • rethrow rethrow关键字可以将异常重新抛出,所以我们不仅可以在发生异常时处理异常,也可以将异常抛出反馈给函数调用者。
      void fun() {
          try {
             throw "null null";
          } catch(e, s) {
             // 对异常进行预处理
             rethrow;
          }
      }
      
      void main() {
          try {
              fun()
          } catch(e) {
              // 函数调用者进行处理
          }
      }
      
  • 8.4 finallyJava类似。

9.类
  • 9.1 构造函数
    • 9.1.1 简化的构造函数 如果不在函数体中做特别的事情,可将函数简化为:
      // 此时必须有“;”
      Bicycle(this.cadence, this.speed, this.gear);
      
      // 等价于
      Bicycle(int cadence, int speed, int gear) {
        this.cadence = cadence;
        this.speed = speed;
        this.gear = gear;
      }
      
    • 9.1.2 默认构造函数 与java一样,Dart会提供一个默认的无参构造函数,在默认构造函数内会默认调用父类的无参构造函数。
    • 9.1.3 重写构造函数 与java类似,Dart也可以创建自己的构造函数。与java一样,自定义构造函数之后,会失去默认的无参构造函数。
      void main() {
        // var a1 = A(); 发生错误,因为无参构造函数被覆盖了
        var a2 = A(1);
      }
      
      class A {
        var i;
        A(this.i);
      }
      
    • 9.1.4 构造函数不能被继承 与java一样,构造函数不能被子类继承。
    • 9.1.5 命名构造函数 除了常规的构造函数外,Dart引入了命名构造函数。我们可能因为不同的目的创建一个类,为构造函数命名有利于更好的识别不同的目的。形式如类名.命名构造函数名字(){方法体},具体如下:
      void main() {
        var p1 = Point(1, 2);
        var p2 = Point.makeFromOtherPoint(p1); // 使用命名构造函数
      }
      
      class Point {
        num x, y;
        Point(this.x, this.y);
      
        // 声明命名构造函数
        Point.makeFromOtherPoint(Point other) {
          x = other.x;
          y = other.y;
        }
      }
      
      由于构造函数不能继承,所以父类的命名构造函数和子类的命名构造函数没有任何关系。
    • 9.1.6 初始化列表 Java会在调用构造函数前,对成员变量进行初始化。同样的Dart中通过初始化列表在构造函数调用前进行初始化。
      class Point {
        final num x;
        final num y;
        final num distanceFromOrigin;
      
        // 初始化例表在构造方法签名后,方法体前
        Point(x, y)
            : x = x,
              y = y,
              distanceFromOrigin = sqrt(x * x + y * y);
      }
      
      注意
      1. 开发时,可以在初始化列表中使用assert进行判断
      2. 初始化列表中,只能使用静态方法
    • 9.1.7 调用父类构造函数 都知道无参的默认构造函数会默认先调用父类的无参构造函数。如果想调用父类的有参构造函数,需在子类的构造函数末尾添加: super(参数),具体如下:
      class A {
        var a = 1;
        A(this.a);
      }
      
      class B extends A {
        final c;
        var d = 4;
        // 调用父类的有参构造函数
        B() : super(1) {}
        
        // 初始化列表和super结合时,super部分应该放在末尾
        B(int p1)
            : c = 3,
              d = 4,
              super(p1) {}
      }
      
      注意
      1. 当初始化列表存在和调用父类的构造函数同时存在时,会优先执行初始化列表 > 父类构造函数 > 子类构造函数。虽然说Dart初始化列表类似Java中对成员变量进行初始化,但在java中父类的构造函数会先于子类的成员变量初始化,而Dart则相反子类的初始化列表先执行。
      2. super()的方法体中允许调用函数,但该函数需为静态函数或者其他非本类和非父类的实例函数,同时不能使用this
    • 9.1.8 调用本类的其他构造函数
      class Point {
        num x, y;
      
        // 类的主构造函数。
        Point(this.x, this.y);
      
        // 指向主构造函数
        Point.alongXAxis(num x) : this(x, 0);
      }
      
    • 9.1.9 常量构造函数 如果一个类的所有对象总是固定不变的,那么可以将这些对象声明为编译期常量。声明为编译期常量,需要将所有属性声明为常量并且声明一个常量构造函数。
      class ImmutablePoint {
        final num x, y;
      
        const ImmutablePoint(this.x, this.y);
      }      
      
      注意 上述步骤只是让一个类具备了成为编译期常量的能力,然而只有正确使用这个能力才能创建编译期常量。如下代码:
      // 方法一:在实例化对象前添加const
      var a = const ImmutablePoint(1, 1); // 创建一个常量对象
      var b = ImmutablePoint(1, 1); // 创建一个非常量对象
      assert(!identical(a, b)); // 两者不是同一个实例!
      
      // 方法二:创建一个常量上下文,此后在常量上下文内创建的对象都为常量(前提是改类型含有常量构造函数)
      const pointsMap = {
        'point1': ImmutablePoint(0, 0),
        'point2': ImmutablePoint(1, 10)
      };
      
    • 9.1.10 工厂构造函数 传统的构造函数都是创建一个新的对象,工厂构造函数让构造函数不再总是创建新对象。工厂构造函数的调用与正常构造函数一样。
      class Logger {
        final String name;
        // _cache 是私有属性。
        static final Map<String, Logger> _cache =
            <String, Logger>{};
      
        Logger(this.name);
      
        factory Logger(String name) {
          if (_cache.containsKey(name)) {
            // 从缓存中获取
            return _cache[name];
          } else {
            // 调用正常的构造函数创建对象并设置到缓存中
            final logger = Logger(name);
            _cache[name] = logger;
            return logger;
          }
        }      
      }
      
      注意 由于工厂构造函数并不总是创建新的对象,所以无法在工厂构造函数内使用this
  • 9.2 getter和setter
    • 9.2.1 默认getter和setter Dart默认为所有变量提供默认getter以及为非常量提供setter方法。
    class Point {
      num x;
    }
    void main() {
      var point = Point();
      point.x = 4; // 实际上调用setter方法进行设置
    }
    
    • 9.2.2 重载getter和setter方法 通过自定义gettersetter添加自己的内容。详细注意点见:
    class Point {
      // 不需要声明变量x
      num get x {
        print("access val x");
        return x;
      }
      set x(num value) {
        print("the x is $value now");
      }
      
      num get y {
        //print("$y");  错误:访问y,导致循环调用y.get()方法,导致栈溢出
        return y;
      }
      set y(num value) {
         //y = value;  错误:设置y,引发栈溢出
         print("$value")// 只能通过value访问
      }
    }
    
    void main() {
      var point = Point();
      point.x = 4; // Use the setter method for x.
    }
    
    注意
    1. 重写的gettersetter方法具有同时声明变量的能力,不需要额外声明变量
    2. getter方法内,除了return语句外,其他地方不能访问该变量
    3. setter方法内,不需要额外使用如y = value的赋值语句,同时只能通过value访问该变量
    4. 如自减、自增等需要多次访问变量的运算符,Dart只会调用一次getter,然后用临时变量暂存避免重复调用引发错误
  • 9.3 抽象类 与Java基本相同。
  • 9.4 隐式接口 Dart中不再显示的提供interface用于声明接口,而是为每一个类隐式的生成接口。即我们可以实现一个普通的类,此时会要求实现该类的所有实例方法(不包括静态方法和构造方法)、gettersetter及该类实现的接口的方法。
    class A {
      void aFun() {
        print("I am aFun in A Class.");
      }
    }
    
    class B implements A {
      fianl b1 = 1;
      var b2 = 2;
    }
    
    class C implements B {
        // 此时会要求实现A.aFun()、B.b1的getter方法、B.b2的getter和setter
    }
    
    如果嫌需要实现的内容太多则通过继承抽象类的方式。
  • 9.5 继承 与Java基本相同。
    • 重写方法 通过@override关键字标记重写方法。
    • 重写运算符 Dart允许对运算符进行重载,这样就可以让两个对象相加了。
      • 允许重写的运算符 <<=>>=+-/~/*%|^&<<>>[](下标访问符)、[]=(下标赋值符)、~==
      • 重写运算符的函数模式 如:返回值 operator 运算符(参数) {方法体} 总体上多了关键字operator并把方法名改为对应要重写的符号
        class Vector {
         final int x, y;
        
         Vector(this.x, this.y);
         
         Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
        }
        
        void main() {
           final v = Vector(2, 3);
           final w = Vector(2, 2);
           assert(v + w == Vector(4, 5));
        }
        
      • 重写== Dart的==类似于Java中的equals方法,所以相同的重写==符号时,需要重写hashCodegetter方法。
  • 9.6 快速扩展类的功能–Mixin
    • 参考文章 混入–Mixin
    • Java中实现接口存在的问题 Java中如果几个类具有相同的功能,我们往往将这些共同的功能抽象为接口,这样有什么问题?Java中往往会出现一种情况就是不同的类需要实现同一个接口,并且实现的代码是一样的,如狗和鸟都需要实现走路这个方法,这样就带来了重复性工作;同时鸟除了走路之外还会飞,所以还需要另外的接口。因此就有较多的接口,较多的方法需要实现
    • Dart的Mixin能解决的问题 Dart中通过Mixin,使得一个类如果需要某个方法或属性,只需简单的通过with TargetClass来快速获取该类的方法。如下代码所示,此时P拥有A的fun1方法,不需要在P中再实现。
       class A {
       	void fun1();
       }
       class P with A 
      
      • 注意点 假设Mixin的多个类中含有相同的方法,则后者会覆盖前者对该方法的实现。
         mixin A {
         	void fun1();
         }
         mixin B {
         	void fun1();
         }
         class P with A, B // A和B具有相同的方法最后P得到的fun1为B中的实现
        

        tip 可通过将A和B的class关键字换为mixin来让A和B只能作为被混入的对象,而不能作为被继承的类

  • 9.7 枚举类 和Java一样,Dart的枚举类不能被继承、实例化。
  • 9.8 获取实例对象的类型 所有类的父类Object提供了一个属性runtimeType用于获取实例的类型。
    print('The type of a is ${a.runtimeType}');
    

万水千山总是情,麻烦手下别留情。
如若讲得有不妥,文末留言告知我,
如若觉得还可以,收藏点赞要一起。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值