类
在Dart中,只要class修饰的,都为类,一个普通的类系统都会给一个默认的构造函数
class Person{
String name;
int age;
}
我们声明了一个类person,但是并没有写他的构造方法,但是我们可以通过Person()来实例化这个对象,这个就是系统默认给的方法
除了系统给的默认构造方法,我们可以自定义构造方法, 一个类只能有一个构造方法,当我们自定义构造方法时候,系统默认的构造方法就不能使用
class Person{
String name;
int age;
// Person(String name, int age){
// this.name = name;
// this.age = age;
// }
Person(this.name, this.age);//上面等同于这里写法
}
这里我们重写了构造方法
| Person(this.name, this.age); |
| var p = Person("lilei",18); |
| 但是日常开发中,我们可能会出现一个类,后期添加了一个新的属性方法,然后我们希望构造的时候传入新的属性的值 |
例
class Person{
String name;
int age;
double height;//假如我后期新加了一个height;
Person2(this.name, this.age);//这里之前已经申明过构造函数了,这时候不能重新写新的构造方法
}
这里我们添加了height,我希望新的初始化对象里传入height的值,这时候我们可以在以前的构造函数里添加一个可选参数height来解决这个需求,也可以通过 .+构造方法的形式,来创建新的构造函数
class Person2{
String name;
int age;
double height;//假如我后期新加了一个height;
Person2(this.name, this.age);//这里之前已经申明过构造函数了,这时候不能重新写新的构造方法
// Person2(this.name, this.age , this height);//因为上面已经有构造函数了,所以这里不能再写,因为Dart不支持重载
// Person2(this.name, this.age,{this.height});//可以通过添加可选参数形式来不改变旧的代码情况下支持新的参数
//假如在不改变上面构造函数的情况下声明一个必须包含height新的构造函数,mustNeedNameAgeHeight是函数名,自定义
Person2.mustNeedNameAgeHeight(this.name,this.age,this.height);
//声明一个map,指定类型key为string,value为dynamic
Person2.getInfoFromMap(Map <String,dynamic>map){
this.name = map["name"];
this.age = map["age"];
this.height = map["height"];
}
}
调用的时候
//类的构造函数
var p2 = Person2.mustNeedNameAgeHeight("lilei1", 18, 68.8)
..log();
var p3 = Person2.getInfoFromMap(
{
"name":"lilei2",
"age":19,
"height":68.5
}
);
..log()中..表示一种链式调用,可以通过..来直接调用类的多个方法
| 类的初始化列表 |
声明一个类,可以在初始化时候直接给一个默认值
class Person{
String name;
int age = 10;//初始化值
Person(String name){
this.name = name;
this.age = 10;//这样和上面都表示默认值为10
}
}
但是当我们的参数是经过final修饰的话,就不能2次修改,通过上面方式给一个初始值的话,就不能从外面赋值,当我们希望根据构造时候传入的参数来判断,有值的话赋值,没有的话给一个默认值,就需要用到下面的构造方法
class Person1{
//这样写也表示默认值,但是这种方式就固定了name age的值,即使外面传入新的值依然赋值不上会报错
// final String name = "lilei";
// final int age = 10;
//final修饰是不可变的,所以这里必须声明时候赋值
final String name ;
final int age ;
//这样写法我就可以在当用户不传入age时候,给个默认值,传入就取传入的值
//大括号里面是在person已经 初始化完成以后调用的,但是final修饰的要求初始化时候就需要赋值,所在在小括号后面直接冒号修饰,后面的内容就表示初始化时候做的事情,age就在初始化时候默认给值18,多个初始化默认值用逗号隔开
Person1 (this.name,{int age}): this.age = age??18;
// Person1 (this.name,{this.age = 10});//这种方式跟上面方式一样,但是区别是这里给的默认值必须是一个确定的值,而上面可以通过表达式获取值,例如:age从int.parse(name)获取,上面可以这么些,这里就不行
}
在构造方法后面直接用:跟上代码。这里的代码就是在初始化完成时候调用,这里判断假如可选参数age没有传递的话,就会给一个默认值,flutter中系统大量使用了这种写法
| 重定向构造函数函数 |
通过上面我们知道给函数创建新的构造方法,以及给默认值的方式,知道了在构造函数后面调用:就是在初始化时候调用的方法
那么现在我们可以将两种方式结合起来,来给对象一个默认初始值
class Person{
final String name;
final int age;
//当我调用这个构造函数时候,我想给age赋一个默认值,上面的方式以外,还可以通过重定向构造函数来实现,通过在初始化时候调用setNameAge构造函数,给age传入默认值0,主力这里修饰name不能直接用this.name,因为当前函数重定向到setNameAge里面了,所以这里构造函数还没有实例化完成,不能使用this.name修饰
Person(String name):this.setNameAge(name,0);
Person.setNameAge(this.name,this.age);
我们可以在:后面调用类的另外一个构造方法,来实现我们所要实现的需求,这种方式就叫做
| 重定向构造函数函数 |
| 常量构造函数 |
在Dart中,我们可以通过const来声明一个函数,这样创造的函数,当传入相同的值时候,系统会帮我们返回一个相同的对象。(mark后期查询资料为什么)
//常量构造函数
class ConstPerson{
final String name;
final age = 19;
//常量构造函数只有一个构造方法,如果有多个参数,其余参数要有默认值
const ConstPerson(this.name);
}
当我们调用时候
const p1 = ConstPerson("1");
const p2 = ConstPerson("1");
print(identical(p1,p2));
打印结果为ture,可以知道p1 p2为同一个对象,这样当我们可以通过同样的值来获取到已有对象,节省内存,但是这样写的弊端非常明显,构造函数只能有一个参数,当多个参数时候,系统会报错
那么有没有一种更加自由的,可以通过同样的值来获取到相同的对象呢,这时候工厂方法就出现了
| 工厂构造函数 |
在Dart中用factory修饰的构造函数都是工厂构造函数,工厂构造函数要求我们必须返回一个当前类的实例对象,否则会报错
class Person {
String name;
String color;
//声明2个map,一个以name为key来存储Person,一个以color为key来存储Person
static final Map<String, Person> _nameCache = {};
static final Map<String, Person> _colorCache = {};
//工厂构造方法要求我们必须手动返回当前生成的对象
factory Person.withNameOrColor({String name,String color}){
print("name $name color$color");
if ((name ==null||name.length ==0) &&(color == null||color.length == 0)) {
return null;
}
if (_nameCache.containsKey(name)&&_colorCache.containsKey(color)) {
//当缓存里包含同样名字或者颜色的person时候,返回缓存里的
var namePerson = _nameCache[name];
var colorPerson = _colorCache[color];
return namePerson??colorPerson;
}else{
//当缓存里都不包含同样名字或者颜色的时候生成一个新的person
//前面《01_类》篇章我们已经说过当重写构造函数的时候,原来默认的构造函数就会失效,所以FactoryPerson()构造函数无法使用,需要我们自定义一个构造函数
final person = Person(name:name,color: color);
if (name!=null&&name.length>0) {
_nameCache[name] = person;
}
if (color!=null&&color.length>0) {
_colorCache[color] = person;
}
return person;
}
}
FactoryPerson({String name, String color}){
this.name = name;
this.color = color;
}
}
在该类中,我们通过创建2个静态的Map来存储以name和color作为值的person对象,当我们传入值时候,首先判断2个map里是否包含同样name以及color的person,当有的话,返回该对象,没有的话创建新的person,添加到map里,并且返回回去,因为factory要求我们必须返回当前类的实例,所以我们需要在添加一个新的构造函数FactoryPerson({String name, String color})来实例化
| setter和getter实现 |
在Dart中某个对象直接调用他的某个参数赋值,获取读取他的某个参数,就是调用的系统默认的setter getter方法,当我们希望在setter和getter调用过程中实现其他的事情的话就需要重写类的setter getter方法
class Person{
//可以在声明时候前面加下划线 _name,但是这样就不能在外面访问该属性
String name;
//setter
set setName(String name){
print("setname");
this.name = name;
}
//getter
// String get getName{
// print("getName");
// return name;
// }
//跟上面一样,但是意义不大,因为这里就跟系统默认的setget方法一样了,无法扩展,上面方法可以在大括号里做set get触发的一些事项
//setter同样可以通过箭头写法
String get getName =>this.name;
}
当我们声明setter getter方法时候,需要在前面加上set和get修饰,这样我们外部直接可以通过set get方法赋值和取值
p.setName = "xiaoming";
print(p.getName);
打印结果
setname
xiaoming
| 类的继承 |
Dart中在类的声明时候通过 extends+类名 的方式,可以继承于某个类
class Person{
String name;
Person(this.name);
}
//student继承于person
class Student extends Person{
int age;
//因为继承于person,所以在student的构造函数里需要先调用person的构造函数
Student(String name,this.age):super(name);
@override
String toString() {
// TODO: implement toString
return "name :$name\nage :$age";
}
}
当继承于某个类的话,就同时拥有父类的属性,但是在内部实现父类属性的调用的话,需要通过super来实现