Dart类和对象

类的定义

// Dart中定义一个类
class Person {
	String name;
	int age;
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
}

Dart中没有privatepublic这些成员访问修饰符类私有的成员 不希望外面访问  在成员变量之前加上 下划线_变为私有

在Dart中还有一种简化写法 可以自动在构造方法中对成员变量初始化

// Dart 定义一个类
class  Person {
	String name;
	int age;
	// 在构造方法中初始化成员变量时 可使用如下写法简化
	Person(this.name, this.age);
	// 如需处理其他变量时 也可单独对其操作
	// Person(this.name, this.age, String address){
	//     print(address);
	// }
	// 注意 构造方法不能重载 以上注释掉
}

Dart中没有构造方法的重载 不能写两个同名的构造方法

Getters 和 Setters方法

使用setter和getter方法来操作类的成员变量Dart 所有类中都包含隐式的getter方法 对于非final修饰的成员 类中还包含隐式的setter方法Dart 可以直接在类外部通过.操作符访问类成员使得Dart语法更加简洁 不会写出满屏的setXXX、getXXX方法

调用setter和getter方法并不仅仅是为了赋值和访问而是为了一些额外的处理这时候 只需要使用setget关键字实现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;
	}
}
void  main() {
	var p = new Person("zhangsan");
	print(p.name);   // user:zhangsan
	p.name = "Jack";
	print(p.name);   // user:Jack
}

创建对象时 new关键字并不是必须的
写Flutter界面时 不建议写new关键字实例化对象
因为Flutter框架中没有类似的xml语言来描述UI界面
界面也是使用Dart语言来写
在使用Dart写UI时 要保持代码的简洁和结构化 省略new会更友好

Dart构造方法

如果没有定义构造方法 则会有一个默认的无参构造方法  且会调用超类的无参构造方法

命名构造方法

Dart类中两个同名构造方法不能重载 但是Dart语言为类新增了一种称为命名构造方法的东西

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可以创建一个编译时常量对象 节省开销

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

工厂构造方法

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

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');
}

构造方法重定向

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

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

类的初始化列表

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);
}

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

  • 初始化列表是由逗号分隔的一些赋值语句组成

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

  • 初始化列表的调用是在构造方法之前 也就是在类完成实例化之前 因此初始化列表中是不能访问 this

运算符重载

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}");
}

打印结果:

8, 15
6, 512

Dart中允许重载的运算符如下:








+*~//%^
<><=>===[][]=
&~<<>>|

类的继承

Dart中的继承 使用关键字extends继承父类 使用关键字super引用父类

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

Dart中的类也只支持单继承但是Dart可以使用一种被称为混入的方式来达到多继承的效果 这需要使用with关键字

// 首先定义三个父类
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 func1234

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

class Son with Father1,Father2,Father3{}

接口抽象

抽象类

Dart语言没有提供interface关键字来定义接口但是Dart语言中保留了抽象类  使用abstract关键字来修饰抽象类

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());
}

Dart 类对象和data-class相关