在学习本篇内容之前请先学习一、半天时间掌握Dart开发语言-基础学习_WEB前端李志杰的博客-CSDN博客 掌握Dart
开发语言的基础。
Dart
是面向对象的编程语言,Dart
中类的很多概念跟其他语言中类的很多概念基本一致,但是Dart
中的类加入一些独有的特性。
文中如有错误之处,还望在评论区指出。
一、定义实例对象属性及实例对象方法
如下示例中,p
为Person
类的实例对象,name
和age
为实例对象上的属性,run()
为实例对象上的方法。
void main() {
Person p = new Person();
p.name = 'lili';
p.run();
}
class Person {
String? name;
int? age;
run() {
print('$name + $age');
}
}
二、类私有属性及私有方法(在定义变量名时在前面加 _
)
私有属性及私有方法只能在类的内部访问和调用,不能通过实例对象访问和调用。
属性及方法私有化的主要目的是为了不让通过实例对象对类的属性值修改,或通过实例对象调用类里面的方法。
如上一个示例中可以使用p.name = 'lili'
直接修改Person
类中name属性的值,也可以通过实例对象p
调用Person
类中的run
方法。
注:同一文件内,实例对象是可以访问类中的私有属性及私有方法的。
// main.dart
void main() {
Person p = new Person();
// 不能通过实例对象p访问_name、_age属性及_run方法
p.name = 'lili'; // 这一行会报错
p.console();
}
// person.dart
class Person {
// 私有属性
String? _name;
int? _age;
// 私有方法
_run() {
print('$_name + $_age');
}
console() {
_run();
}
}
三、静态属性及静态方法
静态属性及静态方法不可以通过实例对象访问,只能通过类名访问。
静态属性不能被构造函数初始化且不能定义为私有属性,即使在变量名前加_
在外部依然可以访问。静态属性在内存中独一份,只要有一处修改静态属性name
的值为lili
,则所有StaticClass.name
的值都是lili
。
静态方法中可以访问静态属性,但是不可以访问实例属性及私有属性。实例方法中既可以访问静态属性也可以访问实例属性。
常量属性(const关键字声明的属性)必须为静态属性(必须使用static修饰)。
void main() {
// 静态属性及静态方法访问
StaticClass._name = 'xuesheng';
StaticClass.run();
// 非静态属性及其方法的访问
StaticClass sc = StaticClass();
sc.run1();
}
class StaticClass {
// 静态属性
static String _name = 'lili';
// 实例属性
int age = 0;
// 静态方法
static run() {
print('$_name');
}
// 实例方法
run1() {
print('$_name+$age');
}
}
四、 构造函数
Dart
中构造函数的函数名与类名相同且不能被显式调用,没有返回值类型、也没有返回值,构造函数在实例对象被创建时自动执行。
当用户没有显式的去定义构造函数时, 编译器会为类生成一个默认的构造函数, 称为 “默认构造函数”, 默认构造函数不能完成对类数据成员(属性和方法)的初始化, 只能给实例对象创建一标识符, 并为实例对象中的数据成员开辟一定的内存空间。
构造函数的主要作用:
构造函数主要用来在创建实例对象时完成对对象属性的一些初始化等操作, 当创建实例对象时, 实例对象会自动调用它的构造函数。
一般来说, 构造函数有以下三个方面的作用:
-
给创建的对象建立一个标识符;
-
为对象数据成员开辟内存空间;
-
完成对象数据成员的初始化。
构造函数分为:无参构造和有参构造,我们主要学习有参构造。
void main() {
Person p = new Person('lili', 20);
p.run();
}
class Person {
String? _name;
int? _age;
// 重写的构造函数
Person(String name, int age) {
_name = name;
_age = age;
}
run() {
print('$_name + $_age');
}
}
构造函数形参和实参一样的情况下,dart可以进行简化开发,如下:
void main() {
Person p = new Person('lili', 20);
p.run();
}
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
run() {
print('$name + $age');
}
}
我们可以结合之前学习的可选参数,实现如下效果。如果构造函数的参数为可选参数则所有 可选参数都必须有默认值,或者标识其为必传。
void main() {
Person p = Person(nameValue: 'lili', ageValue: 18);
p.run();
}
class Person {
String? name;
int? age;
// 构造函数
Person({String nameValue = '', required int ageValue}) {
name = nameValue;
age = ageValue;
}
run() {
print('$name + $age');
}
}
五、命名构造函数
命名构造函数:dart提供的一个新概念,即可以指定一个指定名称的函数作为构造,使用如下:
void main() {
Person p = Person('lili', 18);
p.run();
}
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
// 命名构造函数
Person.init(this.name, this.age);
run() {
print('$name + $age');
}
}
六、初始化列表
初始化列表会在构造函数方法体执行之前执行,多个初始化列表表达式之间使用,
分割。
初始化列表主要作用:对final
修饰的实例对象属性赋值和对构造函数的形参进行校验。
初始化列表常用于设置final修饰的属性的值。
初始化列表中可以使用assert进行判断参数。
先按顺序执行初始化列表中的内容,然后再执行构造函数方法体中的内容。
void main() {
Person p = Person({'name': 'lili', 'age': 18, 'height': 10});
p.run();
}
class Person {
String name;
int age;
int height;
// 命名构造函数
Person(info)
: name = info['name'],
age = info['age'],
height = info['height'] {
print(height > 100);
}
run() {
print('$name + $age + $height');
}
}
七、常量构造函数
类中所有属性都必须使用final
修饰,则可以使用const
修饰构造函数,此时该构造函数为一个常量构造函数。其内部属性的值在构造函数初始化完成之后,所有属性的值是不允许被修改的。
常量构造函数的作用:多次调用常量构造函数时,如果传递一样的实参将获取同一实例对象,从而节省内存开销和运行效率。
注:常量构造函数,只能是类默认的构造函数且必须有参数,所有的属性都必须使用final修饰。
void main() {
Person p = const Person('lili', 18);
Person p1 = const Person('lili', 18);
print(p == p1); // true
p.run();
}
class Person {
final String name;
final int age;
const Person(this.name, this.age);
run() {
print('$name + $age');
}
}
八、工厂构造函数(单例对象)
常量构造函数的弊端就是,构造函数传入的实参必须是一样的,如果多个实参中有一个实参的值不一样,最终都将得到不同的实例对象。
注:工厂构造函数必须用factory
修饰,否则,不能return
。
void main() {
FactoryClass fc1 = FactoryClass();
FactoryClass fc2 = FactoryClass();
print(fc1 == fc2); // true
}
class FactoryClass {
static FactoryClass? _instance;
// 由于构造函数内部不能调用自己,可以使用命名构造函数解决
factory FactoryClass() => _instance ??= FactoryClass.init();
FactoryClass.init();
}
九、 类的继承
Dart
中类的继承会继承除了构造方法以外的所有属性及方法。
void main() {
Student s = Student.init("一年级一班", 'lili', '小李子', 6, 120);
print(s._height);
print(s.age);
print(s.name);
print(s.className);
print(s.subName);
}
class Person {
String name;
int age;
int _height;
bool isFree() => _height < 100;
Person(this.name, this.age, this._height);
getInfo() {
print("姓名:$name,年龄:$age,身高:$_height");
}
}
class Student extends Person {
String className;
String subName;
// 以下这行代码,采用构造函数及初始化列表两种形式完成了对Student类中实例对象属性的初始化工作
Student.init(
this.className, String name, String subNameValue, int age, int height)
: subName = subNameValue,
super(name, age, height);
@override
// 属性重写
bool isFree() => age < 100;
@override
// 方法重写
getInfo() {
return super.getInfo();
}
}
十、抽象类
抽象类不能被实例化,如果只是继承一个抽象类,可使用extends
关键字。如需继承多个抽象类则需要使用implements
关键字。
implements
关键字既可以继承抽象类也可以继承普通类,在继承了普通类之后也需要实现普通类中的所有属性及方法。
// 抽象类
abstract class AbstractClass {
// 抽象方法,抽象方法只能放在抽象类中,抽象方法只能由子类实现
int sum(int value1, int value2);
}
class Class {
int value1;
int value2;
Class(this.value1, this.value2);
int sum1() {
return value1 + value2;
}
}
class SubClass implements AbstractClass, Class {
// 实现抽象类中的方法
@override
int sum(int value1, int value2) {
return value1 + value2;
}
// 实现普通类中的属性和方法
@override
late int value1;
@override
late int value2;
@override
int sum1() {
// TODO: implement sum1
throw UnimplementedError();
}
}
十一、混入Mixins
为了弥补extends
只能继承一个类的不足,dart中新增一个类的特性,即mixins(混入),以实现同时继承多个类的属性和方法。
如果混入的多个类中的属性名或者方法名称一样,则实际为最后一个。
混入的类不可以实现构造方法或继承别的类。
void main() {
SubClass sc = SubClass(10, 20);
print(sc.sum1());
sc.run();
}
class Class1 {
int value1;
int value2;
Class1(this.value1, this.value2);
int sum1() {
return value1 + value2;
}
}
class Class2 {
run() {
print('Class-----');
}
}
class SubClass extends Class1 with Class2 {
SubClass(int value1, int value2) : super(value1, value2);
}
十二、复写操作符运算
可以通过operator
关键字,定义复写的操作运算符。
void main() {
OperatorClass op1 = OperatorClass(28);
OperatorClass op2 = OperatorClass(20);
print(op1 > op2); // true
}
class OperatorClass {
int age;
OperatorClass(this.age);
bool operator >(OperatorClass other) => age > other.age;
}
至此,Dart这门开发语言已经全部介绍完毕,如有疑问可在评论区留言。