Android学Dart学习笔记第十五节 类

文档描述

Dart is an object-oriented language with classes and mixin-based inheritance. Every object is an instance of a class, and all classes except Null descend from Object. Mixin-based inheritance means that although every class (except for the top class, Object?) has exactly one superclass, a class body can be reused in multiple class hierarchies. Extension methods are a way to add functionality to a class without changing the class or creating a subclass. Class modifiers allow you to control how libraries can subtype a class.

Dart是一种基于类和mixin的继承的面向对象语言。每个对象都是某个类的实例,而除Null之外的所有类都是object的后代

基于mixin的继承意味着尽管每个类(除了最上面的类,Object?)都只有一个超类,但一个类的主体可以在多个类层次中重用。

扩展方法是一种向类添加功能而不改变类或创建子类的方法。

类修饰符允许你控制库如何为一个类添加子类型。

信息量极大,暂时不理解没关系,继续看

Using class members 使用类成员

这部分和kt一样

使用点(.)来引用实例变量或方法:

dart 复制代码
var p = Point(2, 2);

// Get the value of y.
assert(p.y == 2);

// Invoke distanceTo() on p.
double distance = p.distanceTo(Point(4, 4));

使用?.而不是.为了避免最左边的操作数为null时发生异常:

dart 复制代码
// If p is non-null, set a variable equal to its y value.
var a = p?.y;

Using constructors

You can create an object using a constructor. Constructor names can be either ClassName or ClassName.identifier.

这点和java略有不同。 在下面例子中的三个函数都是构造函数。ClassName.identifier形式的构造函数,又叫命名构造函数,所有formJson是命名工厂构造函数

dart 复制代码
class Point {
  var x;
  var y;
  // 1. 生成构造函数(Generative Constructor)
  // 最常见的构造函数,直接创建新实例
  Point(this.x, this.y);
  
  // 2. 命名构造函数(Named Constructor)
  // 只是语法糖,仍然是生成构造函数
  Point.origin() : x = 0, y = 0;
  
  // 3. 工厂构造函数(Factory Constructor)
  // 不总是创建新实例,可以返回缓存实例或子类实例
  factory Point.fromJson(Map<String, int> json) {
    return Point(json['x']!, json['y']!);
  }
}

在dart中,new关键字是可选的,两者等价。

dart 复制代码
  final p = new Point(1, 2);
  var newP= Point(1, 2);

有一些类提供了常量构造函数,如下:

dart 复制代码
class ImmutablePoint {
  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

要使用常量构造函数创建编译时常量,请将const关键字放在构造函数名称之前,如下

dart 复制代码
  var c = const ImmutablePoint(1, 2);
  var c1 = const ImmutablePoint(1, 2);
  print(c == c1);//true

如果不需要也可以直接创建

dart 复制代码
var c =  ImmutablePoint(1, 2);
  var c1 =  ImmutablePoint(1, 2);
  print(c == c1);//false

如果一个字段被定义为常量,后面的cosnt是可以省略的

dart 复制代码
 const c =  ImmutablePoint(1, 2);
  const c1 =  ImmutablePoint(1, 2);
  print(c == c1);//true

你可以仔细看看上面3段的区别

下面的官方的例子:

dart 复制代码
// Lots of const keywords here.
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

省略后

dart 复制代码
// Only one const, which establishes the constant context.
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

如果常量构造函数在常量上下文之外(就是不是用的const a,而是var )并且在没有const的情况下调用,它会创建一个非常量对象(并且也不是 var a = const A())

Getting an object's type

要在运行时获取对象的类型,您可以使用Object属性runtimeType,它返回一个Type对象。

dart 复制代码
  const c =  ImmutablePoint(1, 2);
  print('The type of a is ${c.runtimeType}');//The type of a is ImmutablePoint
  

使用类型测试操作符(is, as, is!)而不是runtimeType来测试对象的类型。在正式环境中,obj is A 比ibj.runtimeType更稳定。

Instance variables

dart 复制代码
class Point {
  double? x; // Declare instance variable x, initially null.
  double? y; // Declare y, initially null.
  double z = 0; // Declare z, initially 0.
}

声明为nullable类型的未初始化实例变量的值为null。非空实例变量必须在声明时初始化。

所有实例变量都会生成一个隐式getter方法。没有初始化器的非最终实例变量和后期最终实例变量也会生成一个隐式setter方法。

setter&gettter方法我们在函数那一章学习过,已经忘却的同学可以回顾下(函数

dart 复制代码
class Point {
  double? x; // Declare instance variable x, initially null.
  double? y; // Declare y, initially null.
}

void main() {
  var point = Point();
  point.x = 4; // Use the setter method for x.
  assert(point.x == 4); // Use the getter method for x.
  assert(point.y == null); // Values default to null.
}

初始化一个声明的非晚期实例变量会在实例创建时设置其值,在构造函数及其初始化列表执行之前。因此,非late实例变量的初始化表达式(在=之后)无法访问this

dart 复制代码
double initialX = 1.5;

class Point {
  // OK, can access declarations that do not depend on `this`:
  double? x = initialX;

  // ERROR, can't access `this` in non-`late` initializer:
  double? y = this.x;

  // OK, can access `this` in `late` initializer:
  late double? z = this.x;

  // OK, `this.x` and `this.y` are parameter declarations, not expressions:
  Point(this.x, this.y);
}

late我们之前在学习变量时也学习过,忘却的同学点这里变量

实例变量可以是final,在这种情况下,它们必须只设置一次。在声明时初始化最终的、非晚期的实例变量,可以使用构造函数的参数,也可以使用构造函数的初始化列表:

dart 复制代码
class ProfileMark {
  final String name;
  final DateTime start = DateTime.now();

  ProfileMark(this.name);
  ProfileMark.unnamed() : name = '';
}

如果需要在构造函数体启动后给final实例变量赋值,可以使用下列选项之一:

使用工厂构造函数;

使用late final,但要小心:没有初始化方法的late final会给API添加一个setter。(更多细节点这个文档了解

Implicit interfaces

每个类都隐式定义了一个接口,其中包含该类的所有实例成员及其实现的任何接口。如果您想创建一个支持类B的API而不继承B实现的类A,类A应该实现B接口。

类通过在implements子句中声明一个或多个接口,然后提供这些接口所需的api来实现这些接口。

dart 复制代码
// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final String _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Impostor implements Person {
  String get _name => '';

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

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

这里使我有点懵懵的,有点不太好接受。 我们努力吧。

正如文档所言,每个类都定义了一个隐藏了接口,我可以理解为class,也是一种接口,当当作接口使用时就只有结构是有效的,当作类对象使用时,方法的实现才有效果。

一个类同样可以实现多个接口

dart 复制代码
class Point implements Comparable, Location {
  ...
}

类变量和方法

使用static关键字实现类范围的变量和方法。

Static variables 静态变量
dart 复制代码
class Queue {
  static const initialCapacity = 16;
  // ···
}

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

静态变量在使用之前不会初始化,java是类加载时初始化

Static methods
dart 复制代码
import 'dart:math';

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

  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

同样,因为初始化时机的不同,静态方法不可以调用实例变量或者实例方法。

** 考虑为常见或广泛使用的实用程序和功能使用顶级函数而不是静态方法。**

可以使用静态方法作为编译时常量。例如,可以将静态方法作为参数传递给常量构造函数。

dart 复制代码
class Example {
  final int value;

  const Example(this.value);

  static int staticMethod() => 42;
}

void main() {
  // 传递静态方法作为常量构造函数的参数
  const instance = Example(Example.staticMethod());
  print(instance.value); // 输出: 42
}
相关推荐
Rainman博1 天前
WMS-窗口relayout&FinishDrawing
android
ASKED_20191 天前
Langchain学习笔记一 -基础模块以及架构概览
笔记·学习·langchain
Lois_Luo1 天前
Obsidian + Picgo + Aliyun OSS 实现笔记图片自动上传图床
笔记·oss·图床
(❁´◡`❁)Jimmy(❁´◡`❁)1 天前
Exgcd 学习笔记
笔记·学习·算法
傻小胖1 天前
21.ETH-权益证明-北大肖臻老师客堂笔记
笔记·区块链
baidu_247438611 天前
Android ViewModel定时任务
android·开发语言·javascript
有位神秘人1 天前
Android中Notification的使用详解
android·java·javascript
云小逸1 天前
【nmap源码学习】 Nmap网络扫描工具深度解析:从基础参数到核心扫描逻辑
网络·数据库·学习
·云扬·1 天前
MySQL Binlog落盘机制深度解析:性能与安全性的平衡艺术
android·mysql·adb
独自破碎E1 天前
【BISHI9】田忌赛马
android·java·开发语言