一.类和对象:
Dart是一个面向对象的语言,面向对象中非常重要的概念就是类,类产生了对象。
1.类的定义
/**
* 在Dart中,定义类用class关键字
* 类通常有两部分组成:成员(member)和方法(method)。
* 定义类的伪代码如下:
* class 类名 {
* 类型 成员名;
* 返回值类型 方法名(参数列表) {
* 方法体
* }
* }
*
* 这里有一个注意点: 我们在方法中使用属性(成员/实例变量)时,并没有加this;
* Dart的开发风格中,在方法中通常使用属性时,会省略this,但是有命名冲突时,this不能省略
*
*
* 当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法
* 下面的Person中我们就是在调用这个构造方法.
* 我们也可以根据自己的需求,定义自己的构造方法:
* 注意:**当有了自己的构造方法时,默认的构造方法将会失效,不能使用
* 1.当然,你可能希望明确的写一个默认的构造方法,但是会和我们自定义的构造方法冲突;
* 2.这是因为Dart本身不支持函数的重载(名称相同, 参数不同的方式)
*/
main(List args) {
// var p = Perosn();
var p = Perosn("ws", 10);
print(p.name); //ws
print(p.age); //10
}
class Perosn {
String name;
int age;
//普通构造方法
// Perosn(String name, int age) {
// this.age = age;
// this.name = name;
// }
//语法糖
Perosn(this.name, this.age);
}
2.构造方法:
-
普通构造方法/命名构造方法
/**
* 当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法
* 下面的Person中我们就是在调用这个构造方法.
* 我们也可以根据自己的需求,定义自己的构造方法:
* 注意:**当有了自己的构造方法时,默认的构造方法将会失效,不能使用
* 1.当然,你可能希望明确的写一个默认的构造方法,但是会和我们自定义的构造方法冲突;
* 2.这是因为Dart本身不支持函数的重载(名称相同, 参数不同的方式)
*
*
*
* Object 和dynamic的区别
* Object调用不属于自己的方法,编译时会报错
* dynamic调用不属于自己的方法,编译时不会报错 但是运行时会报错
*
* dynamic它是一种类型 是一个明确类型 和 String int等一样
*/
main(List args) {
//创建person对象
// var p = Perosn();
// var p = Perosn("ws", 10);
var p = Perosn.withNameAgeHeight("ws", 10, 190);
print(p.toString()); //ws 10 190.0
// Object 和dynamic的区别
// ws_dynamicAndObjectAction();
var p1 = Perosn.fromMap({"name": "ws", "age": 29, "height": 1.78});
//重写tostring之前
print(p1); //Instance of 'Perosn'
//重写tostring之后
print(p1); //ws 29 1.78
}
//Object 和dynamic的区别
ws_dynamicAndObjectAction() {
// Object obj = "ws1";
// print(obj.substring(1));//编译时报错
dynamic obj1 = 123;
print(obj1.substring(1)); //编译时不报错 运行时报错
}
class Perosn {
String name = '';
int age = 0;
double height = 0;
// 普通构造方法
// Perosn(String name, int age) {
// this.age = age;
// this.name = name;
// }
//语法糖
// Perosn(this.name, this.age);
// Perosn(this.name, this.age,this.height);
//命名构造方法
Perosn.withNameAgeHeight(this.name, this.age, this.height);
Perosn.fromMap(Map map) {
this.name = map['name'];
this.age = map['age'];
this.height = map['height'];
}
//重写tostring方法
@override
String toString() {
// TODO: implement toString
return '$name $age $height';
// return super.toString();
}
}
-
初始化列表
main(List args) {}
class Person {
String name;
//设置初始值方式1:
int age;
// int age = 10;
//设置初始值方式2:初始化列表
Person(this.name) : age = 10;
}
-
重定向构造方法
main(List args) {
var p = Person("ws");
print('${p.age} ${p.name}'); // 0 ws
}
class Person {
String name;
int age;
//初始化列表
// Person(this.name):age = 0;
//构造函数的重定向
Person(String name) : this._internal(name, 0);
Person._internal(this.name, this.age);
}
-
常量构造方法
/**
* 常量构造方法
* 在某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法.
* ******这里我们使用identical(对象1, 对象2)函数来判断两个对象是否是同一个对象:
*
* 如果将构造方法前加const进行修饰,那么可以保证同一个参数,创建出来的对象是相同的,这样的构造方法就称之为常量构造方法。
*
* 常量构造方法有一些注意点:
* 注意一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的.
* 注意二: 为了可以通过常量构造方法,创建出相同的对象,不再使用 new关键字,而是使用const关键字
* 注意三: 如果是将结果赋值给const修饰的标识符时,const可以省略.
*
*
*/
main(List args) {
Dog p = Dog("xh");
print('name is ${p.name} , age is ${p.age}'); //name is xh , age is 0
var p1 = Person("ws");
var p2 = Person("ws");
print(identical(p1, p2)); //false
var p3 = const Person("ws");
var p4 = const Person("ws");
print(identical(p3, p4)); //true
const p5 = Person("ws");
const p6 = Person("ws");
print(identical(p5, p6)); //true
final ws = Person("ws");
final ws1 = Person("ws");
print(identical(ws, ws1)); //false
}
class Dog {
String name;
int age;
//初始化列表
// Person(this.name) : age = 10;
//重定向构造函数
Dog(String name) : this.initWithData(name, 0);
//命名构造函数
Dog.initWithData(this.name, this.age);
}
class Person {
final String name;
const Person(this.name);
}
-
工厂构造方法
/**
* 普通的构造函数:会默认返回创建出来的对象 不需要写return返回值的
* 工厂构造函数(factory):需要自己手动的返回一个我们的对象
*
*
* 工厂构造函数最大的特点:就是可以手动的返回一个对象
*/
main(List args) {
final s1 = Student("ws");
final s2 = Student("Ws");
print(identical(s1, s2)); //false
final p1 = Person.withName("ws");
final p2 = Person.withName("ws");
final p3 = Person.withName("ws3");
final p4 = Person.withName("ws3");
print(identical(p1, p2)); //true
print(identical(p2, p3)); //false
print(identical(p3, p4)); //true
print(identical(p1, p2)); //true
/**
* 为何使用final修饰对象 而不用var 因为这是命名规范,类似swift 使用let不用var es6使用const
* 不用let 就是防止创建的对象被恶意修改
*/
}
class Student {
String name;
Student(this.name);
}
class Person {
String name;
String color;
static final Map _nameCache = {};
static final Map _colorCache = {};
factory Person.withName(String name) {
if (_nameCache.containsKey(name)) {
// return _nameCache[name];
return _nameCache[name]!;
} else {
final p = Person(name, "default");
_nameCache[name] = p;
return p;
}
}
factory Person.withColor(String color) {
if (_colorCache.containsKey(color)) {
// return _colorCache[color];
return _colorCache[color]!;
} else {
final p = Person("default", color);
_colorCache[color] = p;
return p;
}
}
//自定义构造函数
Person(this.name, this.color);
}
3.类的setter和getter
main(List args) {
final p = Person();
//直接访问属性
p.name = "ws";
print(p.name); //ws
print(p.getName); //ws
//通过setter和getter来访问
p.setName = "ws1";
print(p.getName); //ws1
}
class Person {
String name = "";
//setter 标准写法
set setName(String name) {
this.name = name;
}
//setter的箭头函数写法
// set setName(String name) => this.name = name;
//getter 标准写法
String get getName {
return this.name;
}
//getter 箭头函数的写法
// String get getName => this.name;
}
4.类的继承
Dart中的继承使用extends关键字,子类中使用super来访问父类。
/**
* 1.父类中的所有成员变量和方法都会被继承,,但是构造方法除外。
* 2.子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法)。
* 3.如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super显式调用父类的某个构造方
* 法。
*/
main(List args) {
final p = Person("ws", 29);
print(p.name); //ws
print(p.age); //29
}
class Animal {
int age;
Animal(this.age);
Animal.withDate(this.age);
}
class Person extends Animal {
String name;
Person(this.name, int age) : super(age);
}
5.抽象类
抽象类是使用abstract声明的类
/**
* 抽象类
* 所以在定义很多通用的**调用接口**时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。
* 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。
*
* 抽象方法:在Dart中没有具体实现的方法(没有方法体),就是抽象方法。
* 1.抽象方法,必须存在于抽象类中。
* 2.抽象类是使用abstract声明的类
*
* 注意事项:
* **注意一:**抽象类不能实例化.(不能通过普通的构造函数进行实例化,但是可以通过工厂构造函数进行实例化)
* **注意二:**抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写.
*
*/
main(List args) {
// 抽象类不能实例化.
// final s = Shape();//报错
//可以使用工厂构造函数实例化
// final m = Map();
// final s = Shape();
}
//抽象类
abstract class Shape {
//只有方法的声明,没有方法的实现
int ws_getAreaAction();
//当然也可以有方法的实现
String ws_getInfoAction() {
return "形状";
}
//工厂构造函数
// factory Shape() {
// // return Shape();//此行代码死循环
// }
}
//继承于抽象类,必须实现抽象类中的抽象方法
class Rectangle extends Shape {
@override
int ws_getAreaAction() {
return 100;
}
}
//普通类
class Person {
//普通类必须有方法的实现
// void ws_runAction();//报错
}
6.隐式接口
/**
* Dart中没有哪一个关键字是来定义接口的
* 没有这些关键字interface/protocol
* 默认情况下所有的类都是隐式接口
* Dart只支持单继承
* 当将一个类当做接口使用时,那么实现这个接口的类,必须实现这个接口中的所有方法
*/
main(List args) {
final wm = woman();
wm.ws_runAction(); //跑
wm.ws_flyAction(); //飞
}
abstract class Runner {
ws_runAction();
}
abstract class Flyer {
ws_flyAction();
}
class woman implements Runner, Flyer {
@override
ws_runAction() {
print('跑');
}
@override
ws_flyAction() {
print('飞');
}
}
7.Mixin混入
/**
* Dart中没有哪一个关键字是来定义接口的
*
* 如果混入 父类 和 自己都有相同的方法 执行: 如果自己有就用自己的 自己没有就用混入的 混入没有才用父类的
*/
main(List args) {
final sm = SuperMan();
sm.ws_runAction(); //跑 //混入run
sm.ws_flyAction(); //飞
}
mixin Runner {
void ws_runAction() {
print("跑");
}
}
mixin Flyer {
void ws_flyAction() {
print("飞");
}
}
class Animal {
ws_eatAction() {
print("吃");
}
void ws_runAction() {
print("父类跑");
}
}
class SuperMan extends Animal with Runner, Flyer {
@override
void ws_runAction() {
super.ws_runAction();
print("混入run");
}
}
8.类属性和方法
main(List args) {
var stu = Student();
stu.name = 'ws';
stu.sno = 99;
stu.ws_studyAction();
Student.time = '8点';
// stu.time = '8点'; 错误做法, 实例对象不能访问类成员
Student.ws_attendClassAction();
// stu.ws_attendClassAction(); 错误做法, 实现对象不能访问类方法
}
class Student {
//成员变量
String name = "";
int sno = 0;
//静态属性(类属性)
static String time = "";
//对象方法
ws_studyAction() {
print('$name学习外语');
}
//静态方法(类方法)
static ws_attendClassAction() {
print('去上外语课');
}
}
9.枚举类型
枚举也是一种特殊的类, 通常用于表示固定数量的常量值。枚举使用enum关键字来进行定义。
main(List args) {
final color = Colors.pink;
switch (color) {
case Colors.red:
print("red");
break;
case Colors.blue:
print("blue");
break;
case Colors.green:
print("green");
break;
case Colors.pink:
print("pink");
break;
default:
print('其他颜色');
}
print(Colors.values); //[Colors.red, Colors.blue, Colors.green, Colors.pink]
print(Colors.red.index); //0
print(Colors.pink.index); //3
}
enum Colors { red, blue, green, pink }