类的定义
class 类名 {
类型 成员名;
返回值类型 方法名(参数列表) {
方法体
}
}
定义一个简单的“人”类
class Person {
String name = "张三";
int age = 20;
void getInfo() {
print('我的名字是:${name},我今年${age}');
}
}
void main(List<String> args) {
Person p1 = Person();
p1.getInfo(); //我的名字是:张三,我今年20
}
类里面的this指向
在任何语言里面this指向都是一个比较头疼的问题,但是在dart类里,官方却并不推荐经常使用this,dart建议只有在两种情况下使用this。
类里面的new
在dart里面,官方建议为了减少代码迁移时的痛苦, Dart 语言仍允许使用 new 关键字, 但请考在你的代码中弃用和删除 new 。
- 其中一种情况是要访问的局部变量和成员变量命名一样的时候:
class Person {
String name = "张三";
int age = 20;
void getInfo() {
String name = '李四';
print('我的名字是:${this.name},我今年${age}');
}
}
void main(List<String> args) {
// Person p1 = new Person();
Person p1 = Person();
p1.getInfo(); //我的名字是:张三,我今年20
}
- 还有一种就是使用了重定向
类里面肯定少不了构造函数了。
在dart里面有两种构造函数,一种是默认的构造函数,只能存在一个,可以省略不写,也可以自己定义,自己定义的会覆盖默认的。因为dart语言会自动编写。还有一种是命名构造函数,是自己编写的构造函数,可以写多个。dart里子类不会继承父类的构造函数。
默认构造函数
class Person {
String name = "张三";
int age = 20;
Person(name, age) {
this.name = name;
this.age = age;
print("我是默认的构造函数,对属性进行了赋值操作");
}
void getInfo() {
print('我的名字是:${name},我今年${age}');
}
}
void main() {
Person p1 = Person("李四", 21);
p1.getInfo();
//我是默认的构造函数,对属性进行了赋值操作
//我的名字是:李四,我今年21
}
默认构造函数的语法糖
dart里面提供了一种对构造函数的语法糖,能够更轻易的进行赋值操作。
class Person {
String name = "张三";
int age = 20;
Person(this.name, this.age)
void getInfo() {
print('我的名字是:${name},我今年${age}');
}
}
void main() {
Person p1 = Person("李四", 21);
p1.getInfo();
//我是默认的构造函数,对属性进行了赋值操作
//我的名字是:李四,我今年21
}
自定义构造函数
class Person {
String name = "张三";
int age = 20;
Person(this.name, this.age);
Person.children(this.name, this.age);
Person.elderly(this.name, this.age);
void getInfo() {
print('我的名字是:${name},我今年${age}');
}
}
void main() {
Person p1 = Person.children("大熊", 12);
Person p2 = Person.elderly("鬼谷子", 66);
p1.getInfo(); //我的名字是:大熊,我今年12
p2.getInfo(); //我的名字是:鬼谷子,我今年66
}
初始化列表(Initializer list)
可以在构造函数体执行之前初始化实例变量。 各参数的初始化用逗号分隔。(在“=”右边不能使用this)
class Sum {
int num1 = 0;
int num2 = 20;
final num sum;
Sum(int num1, int num2)
:num1 = num1,
num2 = num2,
sum = num1 + num2;
}
void main() {
Sum s1 = Sum(1,2);
print(s1.sum); //3
}
重定向构造方法
在某些情况下, 我们希望在一个构造方法中去调用另外一个构造方法, 这个时候可以使用重定向构造方法
class Sum {
int num1 = 0;
int num2 = 20;
final num sum;
Sum(int num1, int num2)
:num1 = num1,
num2 = num2,
sum = num1 + num2;
Sum.sum2(int x, int y): this(x, y);
Sum.sum3(int x, int y): this.sum2(x, y);
}
void main() {
//向找到sum3.然后重定向到sum2,最后重定向到sum。
Sum s1 = Sum.sum3(10, 20);
print(s1.sum); //30
}
常量构造方法
默认情况下,创建对象时,即使传入相同的参数,创建出来的也不是同一个对象。
class Point {
late num x;
late num y;
Point(this.x, this.y);
}
void main() {
Point p1 = Point(1,2);
Point p2 = Point(1,2);
print(identical(p1, p2)); //false
}
在某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法。就是在构造方法前加const进行修饰,那么可以保证同一个参数,创建出来的对象是相同的。
class Point {
final num x;
final num y;
const Point(this.x, this.y);
}
void main() {
Point p1 = const Point(1,2);
Point p2 = const Point(1,2);
print(identical(p1, p2)); //false
}
常量注意点:
注意一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的.
注意二: 为了可以通过常量构造方法,创建出相同的对象,不再使用 new关键字,而是使用const关键字,如果是将结果赋值给const修饰的标识符时,const可以省略.
setter和getter
默认情况下,Dart中类定义的属性是可以直接被外界访问的。
但是某些情况下,我们希望监控这个类的属性被访问的过程,这个时候就可以使用setter和getter了。
class Color {
String color = 'green';
Color(this.color);
String get getColor{
return color;
}
void set setColor(String val) {
color = val;
}
}
void main() {
Color c1 = Color("red");
print(c1.getColor); //red
c1.setColor = "black";
print(c1.getColor); //black
}
类的继承
面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。
- Dart中的继承使用extends关键字,子类中使用super来访问父类。
- 父类中的所有成员变量和方法都会被继承,,但是构造方法除外。
- 子类可以重写父类的属性和方法,
- 子类中可以调用父类的构造方法,对某些属性进行初始化:
- 子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法)。
- 如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super显式调用父类的某个构造方法。
class Son extends Father {
String name;
Son(String name) : name = name, super(name);
Money() {
print("我有100美金");
}
getFatherAge() {
print("父亲今年${age}");
}
}
void main() {
Son s1 = Son('fufu');
s1.Money(); //我有100美金
s1.getFatherAge(); //父亲今年50
}
抽象类
使用 abstract
修饰符来定义 抽象类 — 抽象类不能实例化。 抽象类通常用来定义接口,以及部分实现。 如果希望抽象类能够被实例化,那么可以通过定义一个工厂构造函数来实现。
抽象类中一般存在抽象方法。没有方法体只有方法名的就是抽象方法,它一般用于当作一个规范。继承了抽象类子类就必须有抽象类的所有方法。
abstract class Animal {
eat();
run();
}
class Cat extends Animal {
@override
eat() {
print("🐱喜欢吃草");
}
@override
run() {
print("🐱跑起来并不快");
}
}
main() {
Cat c1 = Cat();
c1.eat(); //🐱喜欢吃草
c1.run(); //🐱跑起来并不快
}
注意
注意一:抽象类不能实例化.
注意二:抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写.
隐式接口
Dart中每个类都隐式的定义了一个包含所有实例成员的接口,并且这个类实现了这个接口,如果我们需要A类支持B类的方法的话,我们可以选择继承,但是我们可能不想继承B类,或者已经继承了其他类,我们可以选择实现B类隐式接口。在实际开发中,我们通常使用抽象类作为接口。因为接口与继承抽象类相似,都需要重写被调用方法的所有属性和方法。
abstract class Animal {
eat();
run();
}
class Cat implements Animal {
@override
eat() {
print("🐱喜欢吃草");
}
@override
run() {
print("🐱跑起来并不快");
}
}
main() {
Cat c1 = Cat();
c1.eat(); //🐱喜欢吃草
c1.run(); //🐱跑起来并不快
}
Mixin混入
如果想要一个类的某个方法,用接口的话需要重写类里的所有属性方法,用继承又只能继承一个类,dart不支持多继承,那么这个时候可以使用Mixin混入。
dart中新支持了一个类的特性,即为mixins(混入),按照dart官方的说明,这个混入的特性,可以同时混入多个类的属性和方法,使用混入只需要在类上使用with关键字,并可以混入多个。(注意混入与接口不能一起使用,但是可以与继承一起使用)
class Runner {
run() {
print('在奔跑');
}
}
class Flyer {
fly() {
print('在飞翔');
}
}
class Cat extends Runner with Flyer{
}
main() {
Cat c1 = Cat();
c1.fly(); //在飞翔
c1.run(); //在奔跑
}
类成员和方法
使用 static 关键字实现类范围的变量和方法。也就是我们常说的静态方法和静态属性。
- 静态方法(类方法)不能在实例上使用,因此它们不能访问 this
class Animal {
static String name = '动物';
String color = 'red';
static void type() {
print(Animal.name);
}
run() {
print("${Animal.name}在奔跑");
}
}
void main() {
Animal a1 = Animal();
a1.run(); //动物在奔跑
print(Animal.name);//动物
Animal.type(); //动物
}
注意
静态成员不能访问非静态成员( static 关键字修饰的成员 不能访问 非 static 关键字修饰的成员)
非静态成员可以访问静态成员
枚举类型
枚举类型也称为 enumerations 或 enums , 是一种特殊的类,用于表示数量固定的常量值。
enum Color { red, green, blue }
main(List<String> args) {
// 枚举中的每个值都有一个 index getter 方法, 该方法返回值所在枚举类型定义中的位置(从 0 开始)。
// 例如,第一个枚举值的索引是 0 , 第二个枚举值的索引是 1。
print(Color.red.index); //0
print(Color.green.index); //1
List<Color> colors = Color.values;
print(colors); //[Color.red, Color.green, Color.blue]
}
注意
枚举不能被子类化,混合或实现。
枚举不能被显式实例化。
网友评论