面向对象编程(OOP)的三个基本特征是:封装、继承、多态
-
封装:封装是对象和类概念的主要特性。封装,把客观事物封装成抽象的类,并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则隐藏。
-
继承:面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
-
多态:允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
Dart所有的东西都是对象,所有的对象都继承自Object类。
Dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是Object的子类
创建类
创建
class Person{
String name="张三";
int age=23;
void getInfo(){
print("${this.name}----${this.age}");
}
void setInfo(int age){
this.age=age;
}
}
实例化
// 方式1:var 最开始时就说过了,var定义的变量会自动进行类型推导
var p1 = new Person();
//方式2
Person p2 = new Person();
构造函数
默认构造函数
无参构造函数
class Person{
String name='张三';
int age=20;
//默认构造函数
Person(){
print('这是构造函数里面的内容 这个方法在实例化的时候触发');
}
void printInfo(){
print("${this.name}----${this.age}");
}
}
有参构造函数
class Person{
late String name;
late int age;
//默认构造函数
Person(String name,int age){
this.name=name;
this.age=age;
}
void printInfo(){
print("${this.name}----${this.age}");
}
}
默认构造函数的简写
针对有参构造函数可以进行简写
class Person{
late String name;
late int age;
//默认构造函数的简写
Person(this.name,this.age);
void printInfo(){
print("${this.name}----${this.age}");
}
}
命名构造函数
Dart里面构造函数可以写多个,这个时候我们需要通过命名构造函数来实现。
void main() {
Person p2 = new Person.now(); //命名构造函数
print(p2);
}
class Person {
late String name;
late int age;
//默认构造函数的简写
Person(String name, int age) {
this.name = name;
this.age = age;
print("我是默认构造函数");
}
Person.now() {
print('我是命名构造函数');
}
Person.setInfo(String name, int age) {
this.name = name;
this.age = age;
}
void printInfo() {
print("${this.name}----${this.age}");
}
}
执行结果
类的抽离
Dart中我们可以通过模块化来管理我们的项目
1、新建lib/Person.dart
class Person{
late String name;
late int age;
//默认构造函数的简写
Person(this.name,this.age);
Person.now(){
print('我是命名构造函数');
}
Person.setInfo(String name,int age){
this.name=name;
this.age=age;
}
void printInfo(){
print("${this.name}----${this.age}");
}
}
2、main.dart中引入lib/Person.dart
import 'lib/Person.dart';
void main(){
Person p1=new Person.setInfo('李四1',30);
p1.printInfo();
}
私有方式、私有属性
Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合
但是我们可以使用 _ 把一个属性或者方法定义成私有。
class Animal{
late String _name; //私有属性
late int age;
//默认构造函数的简写
Animal(this._name,this.age);
void printInfo(){
print("${this._name}----${this.age}");
}
String getName(){
return this._name;
}
void _run(){
print('这是一个私有方法');
}
execRun(){
this._run(); //类里面方法的相互调用
}
}
void main(){
Animal a=new Animal('小狗', 3);
print(a._name) //错误:类外部没法访问私有属性
a._run() //错误:类外部没法访问私有方法
print(a.getName()); //正确:通过公有方法访问私有属性
a.execRun(); //正确:间接的调用私有方法
}
关键字 late
查了一下有两个作用:
- 显式声明一个非空的变量,但不初始化
- 延迟初始化变量
大体上就是late
声明的变量必须非空,只有当该变量被使用时才进行初始化。
getter和setter
Dart类中的getter和setter修饰符允许程序分别初始化和检索类字段的值。跟Java中getter和setter功能类型,用来获取和设置字段的值,但是语法上有些不同。
不使用getter和setter修饰符的例子
class Rect{
num height;
num width;
Rect(this.height,this.width);
area(){
return this.height*this.width;
}
}
void main(){
Rect r=new Rect(10,4);
print("面积:${r.area()}");
}
使用getter和setter修饰符的例子
class Rect{
late num height;
late num width;
Rect(this.height,this.width);
get area{ //dart中定义一个getter
return this.height*this.width;
}
set areaHeight(value){ //dart中定义一个setter
this.height=value;
}
}
void main(){
Rect r=new Rect(10,4);
r.areaHeight=6; //调用setter 设置值
print(r.area); //调用getter 获取值
}
注: getter没有参数并返回一个值,setter只有一个参数但不返回值。
静态成员和静态方法
- 使用static 关键字来实现类级别的变量和函数
- 静态方法不能访问非静态成员,非静态方法可以访问静态成员
- 静态属性和静态方法可以直接使用类名称访问。
class Person {
static String name = '张三';
static void show() {
print(name);
}
}
main(){
print(Person.name);
Person.show();
}
对象操作符
class Person {
String name;
num age;
Person(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
as 类型转换
var p1;
p1='';
p1=new Person('张三1', 20);
p1.printInfo();
(p1 as Person).printInfo(); //把p1 string类型转换成Person类型
一开始没报错,但是编译执行时会报错,因此好像没啥用。
is判断类型
Person p=new Person('张三', 20);
if(p is Person){ //判断p是不是Person类型
p.name="李四";
}
p.printInfo();
print(p is Object); //Object类是所有类的基类
… 级联操作
这个比较有意思,跟jquery
的链式操作差不多
Person p1 = new Person('张三', 20);
p1.printInfo();
p1
..name = "李四"
..age = 30
..printInfo();
类的继承
- 子类使用extends关键词来继承父类
- 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
- 子类能复写父类的方法 getter和setter
基本用法
class Person {
String name='张三';
num age=20;
void printInfo() {
print("${this.name}---${this.age}");
}
}
class Web extends Person{
}
main(){
Web w=new Web();
print(w.name);
w.printInfo();
}
实例化子类给父类构造函数传参
class Person {
late String name;
late num age;
Person(this.name,this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
class Web extends Person{
Web(String name, num age) : super(name, age){
}
}
main(){
Web w=new Web('张三', 12);
w.printInfo();
}
实例化子类给命名构造函数传参
class Person {
String name;
num age;
Person(this.name, this.age);
Person.xxx(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
class Web extends Person {
late String sex;
Web(String name, num age, String sex) : super.xxx(name, age) {
this.sex = sex;
}
run() {
print("${this.name}---${this.age}--${this.sex}");
}
}
main() {
Web w = new Web('张三', 12, "男");
w.printInfo();
w.run();
}
子类覆写父类的方法
class Person {
String name;
num age;
Person(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
work() {
print("${this.name}在工作...");
}
}
class Web extends Person {
Web(String name, num age) : super(name, age);
run() {
print('run');
}
//dart子类覆写父类的方法
@override //可以写也可以不写 建议在覆写父类方法的时候加上 @override
void printInfo() {
print("姓名:${this.name}---年龄:${this.age}");
}
@override
work() {
print("${this.name}的工作是写代码");
}
}
main() {
Web w = new Web('李四', 20);
w.printInfo();
w.work();
}
子类里面调用父类的方法
class Person {
String name;
num age;
Person(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
work() {
print("${this.name}在工作...");
}
}
class Web extends Person {
Web(String name, num age) : super(name, age);
run() {
print('run');
super.work(); //子类调用父类的方法
}
//覆写父类的方法
@override //可以写也可以不写 建议在覆写父类方法的时候加上 @override
void printInfo() {
print("姓名:${this.name}---年龄:${this.age}");
}
}
main() {
Web w = new Web('李四', 20);
w.run();
}
抽象类
Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。
1、抽象类通过abstract 关键字来定义
2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
3、如果子类继承抽象类必须得实现里面的抽象方法
4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
5、抽象类不能被实例化,只有继承它的子类可以
extends 和 implements的区别:
1、如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
2、如果只是把抽象类当做标准的话我们就用implements实现抽象类
多态
多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。
abstract class Animal {
eat(); //抽象方法
}
class Dog extends Animal {
@override
eat() {
print('小狗在吃骨头');
}
run() {
print('run');
}
}
class Cat extends Animal {
@override
eat() {
print('小猫在吃老鼠');
}
run() {
print('run');
}
}
main() {
Animal d = new Dog();
d.eat();
Animal c = new Cat();
c.eat();
}
泛型
通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
泛型方法
T可以是任意值,但是一般用用T来定义泛型方法
getData<T>(T value) {
return value;
}
main() {
//字符串
print(getData('这是一个字符串'));
//number类型
print(getData(1));
}
泛型类
class MyList<T> {
List list = <T>[];
void add(T value) {
this.list.add(value);
}
List getList() {
return list;
}
}
main() {
MyList l1 = new MyList<String>();
l1.add("张三1");
print(l1.getList());
}
泛型接口
abstract class Cache<T> {
getByKey(String key);
void setByKey(String key, T value);
}
class MemoryCache<T> implements Cache<T> {
@override
getByKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print("我是内存缓存 把key=${key} value=${value} -写入到了内存中");
}
}
main() {
MemoryCache m = new MemoryCache<Map>();
m.setByKey('index', {"name": "张三", "age": 20});
}