继承
- 使用关键字extends继承一个类
- 子类会继承父类可见的属性和方法,不会继承构造方法
- 子类能够复写父类的方法、getter和setter
- 单继承,多态性
我们定义一个动物类Animal类,具有名字、年龄,还有一个是否食肉的属性,默认为true,还有一个run()方法。
class Animal{
String name;
int age;
bool get eatMeat => true;
void run(){
print("run...");
}
}
定义一个Sheep类集成Animal类,重写食肉属性为false,重写run()方法,另外它还有一个自己的特有方法shout()
class Sheep extends Animal{
//重写父类的属性
@override
bool get eatMeat => false;
//重写父类的方法
@override
void run() {
print("Sheep run...");
}
void shout(){
print("mie mie mie...");
}
}
创建Sheep类并调用其run()方法,由于shout()方法是Sheep类所特有的方法,所以需要先将Animal类型的sheep变量进行转换,可以使用 as 转换,或使用以下的判断:
void main() {
Animal sheep = new Sheep();//使用Animal类接收
sheep.run();//Animal类具有run()方法
if(sheep is Sheep){
//shout()方法为子类Sheep特有,需要转换为子类Sheep才能调用
sheep.shout();
}
}
打印结果为:
Sheep run...
mie mie mie...
继承中的构造方法
- 子类的构造方法默认会调用父类的无名无参构造方法
- 如果父类没有无名无参构造方法,则需要显示调用父类构造方法
- 在构造方法参数后使用:显示调用父类的构造方法
定义一个Person类,包含一个无名构造方法和命名构造方法withAge()
class Person {
String name;
int age;
Person(this.name);
Person.withAge(this.age);
}
定义一个Student类继承Person类,重写其两个构造方法:
class Student extends Person {
Student(String name) : super(name);
Student.withAge(int age) : super.withAge(age);
}
通过两个不同的构造方法构造student实例:
void main() {
var student1 = new Student("chaychan");
var student2 = new Student.withAge(26);
print(student1.name);
print(student2.age);
}
构造方法执行顺序
- 父类的构造方法在子类构造方法体开始执行的位置调用
- 如果有初始化列表,初始化列表会在父类构造方法之前执行
class Student extends Person {
final String gender;
Student(String name) : gender = "Male", super(name);
}
抽象类
- 抽象类用abstract表示,不能直接被实例化
- 抽象方法不需要用abstract修饰,无实现
- 抽象类可以没抽象方法
- 有抽象方法的类一定得声明为抽象类
abstract class Animal {
void run();
}
class Dog extends Animal {
@override
void run() {
print("run...");
}
}
接口
- 类和接口是统一的,类就是接口
- 每个类都隐式的定义了一个包含所有实例成员的接口
class Animal {
String name;
int age;
void run() {
print("run...");
}
}
class Dog implements Animal {
@override
int age;
@override
String name;
@override
void run() {
print("run...");
}
}
可以看到此时Animal类即是接口,Dog类实现这个接口需要复写Animal类的所有属性和方法。
- 如果是复用已有类的实现,使用继承方式(extends)
上述相当于复用已有类的实现,可以使用继承的方法:
class Dog extends Animal {
}
- 如果只是使用已有类的外在行为,使用实现方式(implements)
abstract class Animal {
void run();
}
class Dog implements Animal{
@override
void run() {
print("run...");
}
}
Mixins
- Mixins类似于多继承,是在多类继承中重用一个类代码的方式
- 使用关键字with连接一个或多个mixin
void main() {
var d = D();
d.a();
d.b();
d.c();
}
class A{
void a(){
print("a");
}
}
class B{
void b(){
print("b");
}
}
class C{
void c(){
print("c");
}
}
class D extends A with B, C{
}
可以看到D类通过Mixins继承了A、B、C三个类,同时具有a()、b()、c()方法,使用Mixins的方法需要通过extends一个类和with其他类,不能直接使用with A, B, C。
- 作为Mixins的类不能有显示声明构造方法
class D extends A with B, C{
}
上述D类中B、C是作为Mixins的类,他们不能显示声明构造方法,即只能使用默认的方法,否则编辑器会提示报错。
- 作为Mixins的类只能继承自Object
class C2{
}
class C extends C2{
void c(){
print("c");
}
}
class D extends A with B, C{ //此时C下面会报红
}
操作符覆写
- 覆写操作符需要在类中定义
返回类型 operator 操作符 (参数1,参数2,...){
实现体
return 返回值
}
-
如果覆写==,还需要覆写对象的hashCode getter方法
-
可以覆写的操作符有:
< > <= >=
+ - * / ~/ %
| & ^ << >>
[] []= ~ ==
演示覆写>和[]操作符,比较两个人的大小,通过比较年龄:
void main() {
var p1 = Person(18);
var p2 = Person(20);
print(p1 > p2);
print(p1["aage"]);
}
class Person {
int age;
Person(this.age);
bool operator >(Person person) {
return this.age > person.age;
}
int operator [](String str) {
if ("age" == str) {
return age;
}
return 0;
}
}
打印结果为:
false
0
枚举
- 枚举是一种有穷序列集的数据类型
- 使用关键字enum定义一个枚举
- 常用于代替常量,控制语句
enum Season{
spring,
summer,
autumn,
winter
}
Dart枚举的特性:
- index从0开始,依次累加
- 不能指定原始值
- 不能添加方法
void main() {
print(Season.spring.index);
print(Season.summer.index);
print(Season.autumn.index);
print(Season.winter.index);
}
打印结果为:
0
1
2
3
和Java中的枚举有所不同,Dart中的枚举不能指定原始值和添加方法。
泛型
- Dart中类型是可选的,可使用泛型限定类型
void main() {
var list1 = new List();
list1.add(1);
list1.add("2");
var list2 = new List<int>();
list2.add(1);
list2.add(2);
}
上述代码中,list1没有指定泛型,可以添加任意类型的值,而list2指定了泛型为int,只能添加整数型的值。
- 使用泛型能够有效的减少代码重复(工具方法可以通过传入指定泛型返回对应类型的结果,无需因为需要返回不同类型的结果编写重复代码)
泛型的的使用
- 类的泛型
class DataHelper<T>{
T data;
setData(T data){
this.data = data;
}
}
void main() {
var helper1 = DataHelper<int>();
helper1.setData(1);
var helper2 = DataHelper<String>();
helper2.setData("2");
}
可以看到我们定义了一个DataHelper类,通过传入类的泛型限制传入的data类型。
- 方法的泛型
void main() {
var helper = DataHelper();
helper.checkData<int>(1);
helper.checkData<String>("Hello");
}
class DataHelper{
checkData<T>(T data){
if(data is int){
print("data is int");
}else if(data is String){
print("data is String");
}
}
}
可以看到我们定义了一个需要带有泛型的方法checkData,通过指定泛型限制参数的类型。
好了,关于Dart的入门相关知识点已经介绍完毕,可以尝试去开发和实践了。