Dart类与对象
使用命令行工具
创建新的工程flutter_oop
,创建完成用Android Studio
工具打开
// 进入桌面,把flutter工程放在桌面上
$ cd /Users/wn/Desktop
// 创建flutter_oop工程,指定iOS工程语言为OC
$ flutter create -i objc flutter_oop
flutter_oop
工程中新建lg_person.dart
文件,我们来学习Dart的类和对象
<!-- lg_person.dart文件 -->
/**
* Dart中默认会生成getter和setter方法
* 属性和方法都通过.语法访问
* final修饰的属性必须定义初始值
* */
class LGPerson {
// ?表示属性值可以为空
String? name;
int? age;
// 如果属性没有设置?可以为空,使用LGPerson(this.school);构造的方式也可以防止报错
// String school;
// LGPerson(this.school);
// final修饰的属性必须给初始值,如果不给初始值,也可以使用构造方式防止报错LGPerson(this.type);
final String type = 'aa';
// 私有属性,外界不能访问
int? _height;
void run() {
print('name:$name age:$age');
// run方法内部可以调用自己的对象 方法
_speak();
}
// 添加下划线_ 就是私有方法,外界不能访问
void _speak() {
print('type:$type');
}
// 对象方法不能重载,只要方法名相同,即便参数类型不同,也会报错
// 底层的原理是:方法的名称是寻找方法的唯一标识,这样的编程语言就不能够进行方法的重载
// int run(int a, int b) {
// return a + b;
// }
}
// 添加全局函数
// 同一份文件中,可以访问私有属性和似有方法
// 所谓的私有只是跨文件不能访问
void test() {
LGPerson p = LGPerson();
p._height = 100;
p._speak();
}
//<!-- main.dart文件 -->
import 'package:flutter/material.dart';
// 导入lg_person头文件
import 'lg_person.dart';
/**
* 类和对象
* 使用class关键字声明一个类
* 可以使用new更上构造函数
* 所有的对象都继承Object类
* */
void main() {
LGPerson p = LGPerson();
p.name = 'a';
p.age = 18;
p.run();
// lg_person.dart文件中的全局函数test,在不同文件也可以访问
test();
}
Dart的构造函数
// 案例一:自定义构造函数
<!-- lg_person.dart文件 -->
class LGPerson {
String? _name;
int? _age;
// 定义完类,会有一个默认的构造函数;一旦定义构造函数,默认构造函数就失去作用
// LGPerson (){}
// 自定义构造函数
LGPerson (int age, String name) {
_name = name;
_age = age;
}
void run() {
print('name:$_name age:$_age');
}
}
//<!-- main.dart文件 -->
import 'package:flutter/material.dart';
// 导入lg_person头文件
import 'lg_person.dart';
void main() {
LGPerson p = LGPerson(18, 'aaa');
p.run();
}
// 打印内容
name:aaa age:18
// 案例二
<!-- lg_person.dart文件 -->
class LGPerson {
String? name;
int? _age;
// 自定义构造函数,构造函数中的参数名称与属性名称相同
LGPerson (int age, String name) {
name = name;
_age = age;
}
void run() {
print('name:$name age:$_age');
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'lg_person.dart';
void main() {
LGPerson p = LGPerson(18, 'aaa');
p.run();
}
// 打印内容
name:null age:18
由于构造函数中的参数名称
与类的属性名称
相同,就不知道name
到底指的是哪个,于是name
的打印结果是null
。
// 解决方案一:Dart语法糖,构造函数
LGPerson (this._age, this.name);
// 解决方案二:使用this语法
LGPerson (int age, String name) {
_age = age;
this.name = name;
}
// 打印内容
name:aaa age:18
// 案例三:最终变量不能再次修改值
<!-- lg_person.dart文件 -->
class LGPerson {
String? name;
final int age;
LGPerson(this.age, this.name);
void changeAge(int age) {
this.age = age;
}
void run() {
print('name:$name age:$age');
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'lg_person.dart';
void main() {
LGPerson p = LGPerson(18, 'aaa');
p.run();
p.changeAge(20);
p.run();
}
// 因为age属性是最终变量,所以不能调用changeAge方法修改age值
- 'LGPerson' is from 'package:flutter_oop/lg_person.dart' ('lib/lg_person.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named 'age'.
this.age = age;
^^^
// 案例四:命名构造函数
<!-- lg_person.dart文件 -->
class LGPerson {
String? name;
final int age;
LGPerson.whitName(this.name, this.age);
void run() {
print('name:$name age:$age');
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'lg_person.dart';
void main() {
LGPerson p = LGPerson.whitName('aaa', 18);
p.run();
}
// 打印内容
name:aaa age:18
// 案例五:使用const修饰构造函数,创建常量对象
// 但一个对象的所有成员属性都是用final修饰的时候,那么这个对象可以被创建为常量对象
class LGPerson {
final String name;
final int age;
const LGPerson(this.name, this.age);
void run() {
print('name:$name age:$age');
}
}
Dart的工厂构造&单例对象&初始化列表
使用工厂构造方法
构造单例对象
,新建factory_class.dart
文件
<!-- factory_class.dart文件 -->
class FactoryClass {
// 需要一个单例对象
static FactoryClass? _instance;
// 重写构造函数
// 构造函数是没有return的,如果要想添加retrun,构造函数前面需要添加factory修饰;如果不添加factory就没有办法return
// factory FactoryClass(){
// if(_instance == null) {
// _instance = FactoryClass._init();
// }
// // 防止为空,强制解包
// return _instance!;
// }
// 对上面进行优化1
// factory FactoryClass(){
// _instance ??= FactoryClass._init();
// return _instance!;
// }
// 对上面进行优化2
// factory FactoryClass(){
// return _instance ??= FactoryClass._init();
// }
// 对上面进行优化3
factory FactoryClass() => _instance ??= FactoryClass._init();
// 私有的命名构造函数
FactoryClass._init();
}
// main.dart文件
import 'package:flutter/material.dart';
import 'factory_class.dart';
void main() {
FactoryClass fact1 = FactoryClass();
FactoryClass fact2 = FactoryClass();
print(fact1 == fact2);
}
// 打印内容
true
初始化列表
的使用,新建person.dart
文件
<!-- person.dart文件 -->
// :冒号后面就是初始化列表
// assert 校验传递的参数
// 初始化列表的目的:1. 给final变量赋值
// 2. 校验传递的参数
// 先执行assert校验语句,再执行this.语句,最后执行print打印语句
class Person {
String name;
int age;
final height;
Person(this.name, this.age, int h)
: height = h,
assert(h >= 0),
assert(age >= 0) {
print('name=$name age=$age height=$height');
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'package:flutter_oop/person.dart';
void main() {
Person p = Person('aaa', -1, 180);
}
// 执行报错
// 初始化age的值必须不小于0
Error: Assertion failed: file:///Users/wangning/Desktop/flutter_oop/lib/person.dart:15:12
age >= 0
is not true
// 执行成功
void main() {
Person p = Person('aaa', 20, 180);
}
类方法和对象操作符
类方法
与静态属性
的使用
// 案例一
<!-- static_class.dart文件 -->
class StaticClass {
// 静态属性
static int count = 1;
// 静态方法
static int sum(int a) {
return a + count;
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'package:flutter_oop/static_class.dart';
void main() {
// 直接使用类名访问
StaticClass.count = 10;
print(StaticClass.sum(20));
}
// 打印内容
30
静态方法
中不能使用对象属性
;静态方法是通过类调用的,在类调用方法之前,可能还没有实例化对象,所以实例对象属性不能访问。
// 案例二
class StaticClass {
// 静态属性
static int count = 1;
int currentCount = 0;
// 静态方法
static int sum(int a) {
return a + count + this.currentCount;
}
}
// 运行报错
lib/static_class.dart:8:24: Error: Expected identifier, but got 'this'.
return a + count + this.currentCount;
^^^^
实例方法
中可以使用静态属性
;实例方法调用的时候,类对象一定加载进去了,所以实例方法可以使用静态属性。
// 案例三
class StaticClass {
// 静态属性
static int count = 1;
int currentCount = 0;
// 实例方法
int sum2(int a) {
return a + count + this.currentCount;
}
}
静态属性
在内存中只有一份,通过案例四
进行验证
// 案例四
class StaticClass {
// 静态属性
static int count = 1;
int currentCount = 0;
int sum2(int a) {
return a + count + this.currentCount;
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'package:flutter_oop/static_class.dart';
void main() {
staticDemo();
StaticClass st = StaticClass();
st.currentCount = 1;
print(st.sum2(20));
}
void staticDemo() {
StaticClass st = StaticClass();
st.currentCount = 10;
StaticClass.count = 11;
print(st.sum2(20));
}
// 打印内容
41
32
常量属性
// 案例五:常量属性
class StaticClass {
// 静态属性
static int count = 1;
// 实例属性
int currentCount = 0;
// 常量属性,在常量区只有一份,所以要用static修饰
static const String str = 'aaa';
// 静态方法
static int sum(int a) {
return a + count;
}
// 实例方法
int sum2(int a) {
return a + count + this.currentCount;
}
}
动态对象添加?
防止空对象调用方法报错
// 案例六:动态对象添加?防止空对象调用方法报错
void main() {
staticDemo();
}
void staticDemo() {
// dynamic 动态对象
var s1;
s1 = StaticClass();
print(s1.sum2(10));
s1 = null;
// 添加?防止空对象调用方法报错
print(s1?.sum2(10));
}
// 打印内容
11
null
强制类型转换
只在使用的那一行有效,哪里调用就在哪里强制转换
// 案例七:强制类型转换
void main() {
staticDemo();
}
void staticDemo() {
var s1 = Object();
s1 = StaticClass();
print((s1 as StaticClass).sum2(10)); // 强制类型转换
// 也可以判断对象类型再调用方法
// if (s1 is StaticClass) {
// print(s1.sum2(10));
// }
}
// 打印内容
11
void staticDemo() {
var s1 = Object();
s1 = StaticClass();
print((s1 as StaticClass).sum2(10));
// s1 = null;
// 添加?防止空对象调用方法报错
print(s1.sum2(10));
}
// 打印内容
11
11
void staticDemo() {
var s1 = Object();
s1 = StaticClass();
print((s1 as StaticClass).sum2(10));
s1 = null;
}
// 运行报错,已经是Object对象就不能被赋值为null
lib/main.dart:12:8: Error: The value 'null' can't be assigned to a variable of type 'Object' because 'Object' is not nullable.
- 'Object' is from 'dart:core'.
s1 = null;
^
链式编程思想
..语法
void main() {
staticDemo();
}
void staticDemo() {
var s1 = Object();
s1 = StaticClass();
// 判断对象类型再调用方法
if (s1 is StaticClass) {
print(s1.sum2(10));
print(s1..currentCount = 15..sum2(20));
// s1..currentCount = 15解析
// 第一步:s1.currentCount = 15;
// 第二步:执行完第一步之后,返回对象本身
// 返回对象,在调用sum2方法
// 执行完sum2方法之后,再次返回对象本身,最终打印出对象
}
}
// 打印内容
11
Instance of 'StaticClass'
Dart的继承
// person.dart文件
// 父类Person
class Person {
String? name;
int? age;
int? _height;
// 计算属性
bool get isFree => _height! < 110;
run() {
print('Person run.....');
}
}
// main.dart文件
import 'package:flutter/material.dart';
import 'package:flutter_oop/person.dart';
void main() {
extendsDemo();
}
void extendsDemo() {
Student st = Student();
st.run();
st.study();
st.name = 'aaa';
st.age = 18;
print(st.isFree);
}
/*
* Dart中的继承
* 使用extends继承一个类
* 子类会继承除了构造方法以外的属性和方法
* Dart是单继承的
* */
class Student extends Person {
study() {
print('认真学习!');
}
// @override就是重写父类的标识,也可以删掉该标识(不推荐)
@override
// TODO: implement isFree
// 重写父类计算属性
bool get isFree => age! < 18;
}
// 打印内容
Person run.....
认真学习!
false
用父类Person
指向st
,并重写父类run
方法
import 'package:flutter/material.dart';
import 'package:flutter_oop/person.dart';
void main() {
extendsDemo();
}
void extendsDemo() {
// 用父类Person指向st,这就是多态
Person st = Student();
st.run();
if (st is Student) {
st.study();
st.name = 'aaa';
st.age = 17;
print(st.isFree);
}
}
class Student extends Person {
study() {
print('认真学习!');
}
// 写在study方法下面,输入run重写父类方法会有提示
@override
run() {
// TODO: implement run
print('Student Run.....');
}
// @override就是重写父类的标识
@override
// TODO: implement isFree
// 重写父类计算属性
bool get isFree => age! < 18;
}
// 打印内容
Student Run.....
认真学习!
true
// Dart中所有的类都继承Object,Person继承自Object,只是继承于Object的类可以省略extends Object
class Person extends Object
Object
类中有一个方法toString
,类似于OC中的description
描述
void extendsDemo() {
Person st = Student();
st.run();
if (st is Student) {
st.study();
st.name = 'aaa';
st.age = 17;
print(st.isFree);
print(st);
}
}
// 打印内容
Student Run.....
认真学习!
true
Instance of 'Student'
// Student类重写toString方法
class Student extends Person {
study() {
print('认真学习!');
}
@override
run() {
// TODO: implement run
print('Student Run.....');
}
// @override就是重写父类的标识
@override
// TODO: implement isFree
// 重写父类计算属性
bool get isFree => age! < 18;
@override
String toString() {
// TODO: implement toString
return 'Student extends Person';
}
}
// 再次运行extendsDemo方法查看打印,变成了toString描述
Student Run.....
认真学习!
true
Student extends Person
子类
会自动继承父类的默认构造方法
// person.dart文件
class Person extends Object {
Person() {
print('Person 构造!');
}
String? name;
int? age;
int? _height;
// 计算属性
bool get isFree => _height! < 110;
run() {
print('Person run.....');
}
}
// main.dart文件
void extendsDemo() {
Person st = Student();
st.run();
if (st is Student) {
st.study();
st.name = 'aaa';
st.age = 17;
print(st.isFree);
print(st);
}
}
// 打印内容,说明子类会自动继承父类的默认构造方法
Person 构造!
Student Run.....
认真学习!
true
Student extends Person
自定义Person
的构造函数
// person.dart文件
class Person extends Object {
Person(this.age);
Person.init();
Person.withName(this.name);
String? name;
int? age;
int? _height;
// 计算属性
bool get isFree => _height! < 110;
run() {
print('Person run.....');
}
}
// main.dart文件中的Student类
class Student extends Person {
// 初始化列表主要是用来给final赋值
final String subName;
// 把subName的值赋上去,注意!! 初始化列表必须放在super前面,否则报错
Student.withName(String? name) : subName = name!, super.withName(name);
// 父类Person的三个构造方法必须实现一个,否则报错
// Student.withName(String? name) : super.withName(name);
// Student.init() : super.init();
// Student(int? age) : super(age);
// 父类的三个构造方法必须显性实现一个,其实主要是实现 super方法;下面是Strudent的一个无参构造方法,只要继承 :super即可
// 这里的 : 有点类似初始化列表
// subName赋个默认值aaa
Student() : subName = 'aaa', super.init();
study() {
print('认真学习!');
}
// 写在study方法下面,输入run重写父类方法会有提示
@override
run() {
// TODO: implement run
print('Student Run.....');
}
// @override就是重写父类的标识
@override
// TODO: implement isFree
// 重写父类计算属性
bool get isFree => age! < 18;
@override
String toString() {
// TODO: implement toString
return 'Student extends Person';
}
}
Dart的抽象类和接口
抽象类
类似于Swift
中的面向协议开发
// 案例一
// main.dart文件
import 'package:flutter/material.dart';
void main() {
abstractDemo();
}
/*
* 抽象类
* 不能被实例化的类,使用abstract修饰
* */
void abstractDemo() {
AbstractClass as = SubClass();
as.sum(10, 20);
}
abstract class AbstractClass {
// 这就是抽象方法
int sum(int a, int b);
}
// 子类要想继承抽象类,必须实现抽象类中的方法
class SubClass extends AbstractClass {
@override
int sum(int a, int b) {
print('a + b = ${a+b}');
return a + b;
}
}
// 打印内容
a + b = 30
使用implements
实现抽象类中的多继承
import 'package:flutter/material.dart';
void main() {
abstractDemo();
}
/*
* 抽象类
* 不能被实例化的类,使用abstract修饰
* */
void abstractDemo() {
SubClass as = SubClass();
as.sum(10, 20);
as.sum1(20, 30);
}
abstract class AbstractClass {
int sum(int a, int b);
}
abstract class AbstractClass1 {
int sum1(int a, int b);
}
abstract class AbstractClass2 {
int sum2(int a, int b);
}
class a {
var name;
run() {
print('haha');
}
}
// 使用implements实现 抽象类的多继承,implements类似于接口
class SubClass implements AbstractClass, AbstractClass1, AbstractClass2, a {
@override
int sum(int a, int b) {
print('subClass..sum');
return 0;
}
@override
int sum1(int a, int b) {
print('subClass..sum1');
return 0;
}
@override
int sum2(int a, int b) {
print('subClass..sum2');
return 0;
}
@override
var name;
@override
run() {
// TODO: implement run
throw UnimplementedError();
}
}
// 打印内容
subClass..sum
subClass..sum1
注意!! 虽然使用implements
也可以实现普通类的属性与方法
,但是不推荐
这样使用。
Mixins混入
Mixins混入
其实就是多继承。
// 案例一
import 'package:flutter/material.dart';
void main() {
mixinDemo();
}
void mixinDemo() {
D d = D();
d.a();
d.b();
d.c();
}
class A{
a() => print('a.....');
}
class B{
b() => print('b.....');
}
class C{
c() => print('c.....');
}
// D继承于A, B/C就是D的混入类
class D extends A with B, C {}
// 打印内容
a.....
b.....
c.....
// 案例二:A/B/C 三个类中的方法全部命名为a
import 'package:flutter/material.dart';
void main() {
mixinDemo();
}
void mixinDemo() {
D d = D();
d.a();
}
class A{
a() => print('a.....');
}
class B{
a() => print('b.....');
}
class C{
a() => print('c.....');
}
// D继承于A, B/C就是D的混入类
class D extends A with B, C {}
// 打印内容,因为C类是最后一个,会覆盖掉前面的方法
c.....
作为混入类不能实现构造方法
// 案例三
class C{
// 构造方法
C();
a() => print('c.....');
}
// D继承于A, B/C就是D的混入类
class D extends A with B, C {}
lib/main.dart:26:7: Error: Can't use 'C' as a mixin because it has constructors.
class D extends A with B, C {}
^
lib/main.dart:21:3: Context: This constructor prevents using 'C' as a mixin.
C();
^
作为混入类,最好不要继承其他类
要继承Object
类,不能继承实现了带参构造方法
的类。
class TestClass {
var name;
TestClass(this.name);
}
class C extends TestClass {
a() => print('c.....');
}
// D继承于A, B/C就是D的混入类
class D extends A with B, C {}
// 运行报错
/*
lib/main.dart:30:7: Error: The non-abstract class 'D' is missing implementations for these members:
- TestClass.name
Try to either
- provide an implementation,
- inherit an implementation from a superclass or mixin,
- mark the class as abstract, or
- provide a 'noSuchMethod' implementation.
class D extends A with B, C {}
^
lib/main.dart:21:7: Context: 'TestClass.name' is defined here.
var name;
^^^^
lib/main.dart:25:7: Error: The superclass, 'TestClass', has no unnamed constructor that takes no arguments.
class C extends TestClass {
^
Unhandled exception:
NoSuchMethodError: The getter 'fileOffset' was called on null.
Receiver: null */
如果D
类中没有自己的成员属性
和方法
,就可以这样写
// D继承于A, B/C就是D的混入类
// class D extends A with B, C {}
// 如果D类中没有自己 的成员属性 和方法,就可以这样写
class D = A with B, C;
重载操作符operator
,通过对象属性
比较两个对象的大小
import 'package:flutter/material.dart';
void main() {
operatorDemo();
}
// 操作符
void operatorDemo() {
OperatorClass op1 = OperatorClass(18);
OperatorClass op2 = OperatorClass(20);
print(op1 > op2);
}
class OperatorClass {
int age;
OperatorClass(this.age);
// 重载操作符operator,通过对象属性比较两个对象的大小
bool operator >(OperatorClass other) => this.age > other.age;
}
// 打印内容
false