开发语言嘛,面向过程和面向对象。dart是面向对象的。
什么是面向对象???
面向对象编程(OOP)的三个基本特征是:封装、继承、多态
Dart所有的东西都是对象,所有的对象都继承自Object类。
用class
关键字去创建,比如说我们要创建一个Person类可以这样写:
class Person{
String name="张三";
int age=23;
void getInfo(){
// print("$name----$age");
print("${this.name}----${this.age}");
}
void setInfo(int age){
this.age=age;
}
构造方法就是在函数内部重写这个类名后面并且带上类中需要的参数,这样外部在new这个类的时候就必须向这个类传入对应的参数,从而达到外部传值的作用。
class Person{
String name;
int age;
//默认构造函数的简写
Person(this.name,this.age);
void printInfo(){
print("${this.name}----${this.age}");
}
}
class Person{
String name;
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}");
}
}
外部调用
Person p1=new Person.now();
tips: 跟kotlin的扩展函数有点像。
set设置属性的值,get拿取属性的值。
在类中,实用static关键字来实现类级别的变量和函数,静态方法可以访问静态成员。
class Person {
static String name = '张三';
static void show() {
print(name);
}
}
main(){
print(Person.name);
Person.show();
}
注意:
class Person {
static String name = '张三';
int age=20;
static void show() {
print(name);
}
void printInfo(){ /*非静态方法可以访问静态成员以及非静态成员*/
// print(name); //访问静态属性
// print(this.age); //访问非静态属性
show(); //调用静态方法
}
static void printUserInfo(){//静态方法
print(name); //静态属性
show(); //静态方法
//print(this.age); //静态方法没法访问非静态的属性
// this.printInfo(); //静态方法没法访问非静态的方法
// printInfo();
}
简单继承,用extends 关键字
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();
}
Dart中的继承我们要注意:
super关键字我们用来调用父类的属性或者方法:
class Person {
String name;
num age;
Person(this.name,this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
class Web extends Person{
String sex;
Web(String name, num age,String sex) : super(name, age){
this.sex=sex;
}
run(){
print("${this.name}---${this.age}--${this.sex}");
}
}
main(){
Person p=new Person('李四',20);
p.printInfo();
Person p1=new Person('张三',20);
p1.printInfo();
Web w=new Web('张三', 12,"男");
w.printInfo();
w.run();
}
控制台打印:
李四---20
张三---20
张三---12
张三---12--男
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{
String sex;
//super自定义构造函数
Web(String name, num age,String sex) : super.xxx(name, age){
this.sex=sex;
}
run(){
print("${this.name}---${this.age}--${this.sex}");
}
}
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');
}
//覆写父类的方法
@override //可以写也可以不写 建议在覆写父类方法的时候加上 @override
void printInfo(){
print("姓名:${this.name}---年龄:${this.age}");
}
@override
work(){
print("${this.name}的工作是写代码");
}
}
main(){
Web w=new Web('李四',20);
w.printInfo();
w.work();
}
继承是面向对象中比较重要的特征之一,在这里希望把继承的方法都记住。在开发中会受益颇深!
Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。
注意:
和Java一样,dart也有接口,但是和Java还是有区别的。
在Dart中需要实现多个接口我们通常需要implement多个abstract类
//Dart中一个类实现多个接口:
abstract class A{
String name;
printA();
}
abstract class B{
printB();
}
class C implements A,B{
@override
String name;
@override
printA() {
print('printA');
}
@override
printB() {
// TODO: implement printB
return null;
}
}
void main(){
C c=new C();
c.printA();
}
mixins的中文意思是混入,就是在类中混入其他功能。在Dart中可以使用mixins实现类似多继承的功能。
因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:
class A {
String info="this is A";
void printA(){
print("A");
}
}
class B {
void printB(){
print("B");
}
}
class C with A,B{
}
void main(){
var c=new C();
c.printA();
c.printB();
print(c.info);
}
如果是基类有构造方法如下,我们只需要重写一下构造方法即可
class Person{
String name;
num age;
Person(this.name,this.age);
printInfo(){
print('${this.name}----${this.age}');
}
void run(){
print("Person Run");
}
}
class A {
String info="this is A";
void printA(){
print("A");
}
void run(){
print("A Run");
}
}
class B {
void printB(){
print("B");
}
void run(){
print("B Run");
}
}
class C extends Person with B,A{
C(String name, num age) : super(name, age);
}
void main(){
var c=new C('张三',20);
c.printInfo();
// c.printB();
// print(c.info);
c.run();
}
泛型,说通俗点:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
举个例子:
//只能返回string类型的数据
String getData(String value){
return value;
}
//只能返回int类型的数据
int getData1(int value){
return value;
}
在开发中,如果只有返回值不同而我们写两遍一样的方法那么则造成了冗余。我们可以用泛型来解决这一问题。
//指定类型放弃了类型检查。我们现在想实现的是传入什么 返回什么。比如:传入number 类型必须返回number类型 传入 string类型必须返回string类型
// T getData(T value){
// return value;
// }
getData(T value){
return value;
}
void main(){
// print(getData(21));
// print(getData('xxx'));
// getData('你好');
print(getData(12));
}
泛型类和泛型方法如出一辙就是将规定的类的类型名传入从而达到控制类的类型的目的
class PrintClass{
List list=new List();
void add(T value){
this.list.add(value);
}
void printInfo(){
for(var i=0;i();
p.add(12);
p.add(23);
p.printInfo();
}
Dart中的泛型接口:实现数据缓存的功能:有文件缓存、和内存缓存。内存缓存和文件缓存按照接口约束实现。
abstract class Cache{
getByKey(String key);
void setByKey(String key, T value);
}
class FlieCache implements Cache{
@override
getByKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print("我是文件缓存 把key=${key} value=${value}的数据写入到了文件中");
}
}
class MemoryCache implements Cache{
@override
getByKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print("我是内存缓存 把key=${key} value=${value} -写入到了内存中");
}
}
void main(){
MemoryCache m=new MemoryCache
前面介绍Dart基础知识的时候基本上都是在一个文件里面编写Dart代码的,但实际开发中不可能这么写,模块化很重要,所以这就需要使用到库的概念。
在Dart中,库的使用时通过import关键字引入的。
library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。
Dart中的库主要有三种:
1、我们自定义的库
import 'lib/xxx.dart';
2、系统内置库
import 'dart:math';
import 'dart:io';
import 'dart:convert';
3、Pub包管理系统中的库
https://pub.dev/packages
https://pub.flutter-io.cn/packages
https://pub.dartlang.org/flutter/
1、需要在自己想项目根目录新建一个pubspec.yaml
2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
3、然后运行 pub get 获取包下载到本地
4、项目中引入库 import 'package:http/http.dart' as http; 看文档使用
具体的math库中是一些数学方法和数学计算,在这里我就不再罗列,只举两个例子,具体可以去查看Dart的官方文档,上面会有很详细的解说,具体我我后面有时间再用一篇文章来罗列所有的math方法
import "dart:math";
main(){
print(min(12,23));
print(max(12,25));
}
这两个关键字的使用只需要记住两点:
async 是让方法变成异步。
await 是等待异步方法执行完成。
void main() async{
var result = await testAsync();
print(result);
}
//异步方法
testAsync() async{
return 'Hello async';
}
可以在需要的时候再进行加载。懒加载的最大好处是可以减少APP的启动时间。
懒加载使用deferred as关键字来指定,如下例子所示:
import 'package:deferred/hello.dart' deferred as hello;
//当需要使用的时候,需要使用loadLibrary()方法来加载:
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
示例:
void printInfo(name,age){
print("$name,$age");
}
//调用
printInfo("leon",17)//caoxiaozhu,17
如果在一个方法中调用了另外一个方法,我们通常在外部就不能直接调用那个方法内部的方法,这句话听起来比较绕口,简单来说,嵌套方法我们只能调用最外层的方法:
void xxx(){
aaa(){
print(getList());
print('aaa');
}
aaa();
}
上述就是一个简单的嵌套方法,那我们在外部调用时,我们不能直接调用xxx方法中的aaa,而只能调用xxx,我们在调用aaa时,Dart就会报错,说明我们不能跨域操作。
在方法传参中跟我们上述介绍的自定义方法有点如出一辙,我们可以指定参数类型,也可以不指定参数类型。具体说起来我们可以将外部的数据传入方法体中进行进一步的操作。
//1、定义一个方法 求1到这个数的所有数的和
int sumNum(int n){
var sum=0;
for(var i=1;i<=n;i++)
{
sum+=i;
}
return sum;
}
//调用
sumNum(100)//求1到100的和
我们除了上述必须传参的函数之外我们还可以创建可选参数传入,也就是说上述必传参函数我们必须要传入定义的参数,但是可选传参函数我们则可以选择性的传入需要的参数,就算不传参系统也不会报错,在可选传参函数中我们用[]
来表示可选参数的传入。
String printUserInfo(String username,[int age]){ //行参
if(age!=null){
return "姓名:$username---年龄:$age";
}
return "姓名:$username---年龄保密";
}
//age为可选参数
外部调用
print(printUserInfo('张三',21))//张三 21
print(printUserInfo('张三'))//张三
在开发中我们还有一种需求就是有一个参数我们可以不必每次都传入新的数据,而是有些情况下参数相对的都一样,那么我们则可以用默认值来代替某一次参数的传入。我们直接在参数后面接一个=
并且附上你需要的默认值。
String printUserInfo(String username,[String sex='男',int age]){ //行参
if(age!=null){
return "姓名:$username---性别:$sex--年龄:$age";
}
return "姓名:$username---性别:$sex--年龄密";
}
//调用
print(printUserInfo('张三'))//姓名:张三---性别:男--年龄保密
print(printUserInfo('小李','女'))//姓名:小李---性别:女--年龄保密
print(printUserInfo('小李','女',30))//姓名:小李---性别:女--年龄:30
Dart中的箭头函数必须满足在function代码块中只执行一句语句,才能使用箭头函数,如果超过一句话语则不能使用箭头函数,如:
//需求:使用forEach打印下面List里面的数据
List list=['苹果','香蕉','西瓜'];
list.forEach((value){
print(value);
});
list.forEach((value)=>print(value));
//箭头函数只打印一句话
list.forEach((value)=>{
print(value)
});
在上述打印方法中我们还可以将箭头函数缩略写成
list.forEach((value)=>print(value));
匿名函数区别于普通函数的最大的地方就是匿名函数没有函数名作为支撑。可以直接将函数附给一个变量,通过变量来执行代码块。不过在实际开发中用的比较少,如果按照规范来的话不太推荐大家用匿名函数。
var printNum=(){
print(123);
};
printNum();
顾名思义,自动执行的方法,但是不知道什么时候会用 @_@。。
((int n){
print(n);
print('我是自执行方法');
})(12);
首先我们来说一个场景:
举个例子:
//全局变量
var a=123;
void main(){
print(a);
fn(){
a++;
print(a);
}
fn();
fn();
fn();
}
//在main的外层有个全局变量a,我们如果调用fn会使a的值一直增加
因为a常驻内存,所以很多地方都可以调用a这个变量,导致了污染全局。保证不了数据的安全。所以我们想办法让a变为内部变量,防止外部的调用,这样闭包就有了意义。
fn(){
var a=123; /*不会污染全局 常驻内存*/
return(){
a++;
print(a);
};
}
var b=fn();
b();
b();
b();
在实际开发中,我们可以将变量写在一个方法体内,保证了变量的的作用域仅限于方法体内,外部并不能调用a。从而使得数据变得相对安全。不会导致任何地方都能用a的值。
结束。