Flutter学习(三:方法、异常、类)

一:方法

Dart语言中定义方法的时候,如果不定义参数类型,可以传入任何类型。并且Dart中不支持方法重载。
例如:三种定义方法的方式

int fun(int i, int j) {
  return i + j;
}
//也可以不写参数类型,即为Object类型参数
fun( i, j) {
  return i + j;
}
//对于只有一个表达式的方法,可以选择使用简写语法来定义:
//在方法体后加入 =>表达式;(只能使用一个表达式)
fun(i, j) => i + j;

匿名方法

有返回值匿名方法
//调用fun方法,传入一个方法
String str = fun((String str) {
 //执行anonymityMethod方法,返回数据
  return str;
});

String fun(String anonymityMethod(String str)) {
  //调用anonymityMethod方法
  return anonymityMethod("调用匿名方法");
}
无返回值匿名方法
fun((String str) {
  print(str);
});
String fun(void anonymityMethod(String str)) {
  anonymityMethod("调用匿名方法");
}

一等方法对象

Dart语言是一门面向对象的语言,方法也是对象,类型为Function。

Function对象代码方法
void fun(String str1, String str2) {
 print("fun方法-------" + str1 + str2);
}
//方法也是对象,类型是Function
Function f = fun;//fun方法是Function类型对象
f("参数1", "参数2");//调用fun方法

在Dart中的方法也是对象,类型是属于Function类型的。那么如果方法的参数为方法呢?那该如何表示?

/**
 * fun1方法参数为Function类型,那么该如何调用fun1方法呢?
 */
void fun1(Function f) {
  f("参数");//❌运行报错,调用fun1时传入的匿名方法有两个参数,所以会参数异常
  f(1, "参数");//Function无法表示传递而来的这个方法参数有几个,所以无法编译时检查
}

Function f1 = fun1;
f1();//❌报错,参数fun1需要一个Function类型参数,所以参数异常
//调用fun1方法,传入一个匿名方法,有点像lamda表达式
f1((int i, String s) {
   return bool;        
});

在调用参数类型为Function的方法时,可以传入匿名方法,这样使用起来比较麻烦。而且Function无法表示方法的参数和返回值,所以编译时检查不出来,运行时才报错。这样使用起来不是很方便,那该如何解决这个问题呢?

typedef关键字
/**
 * typedef关键字:
 * 定义"DEF"方法类型,此时"DEF"其实就是一个含有int、String参数和String返回值的方法类
 * 型,DEF就可以表示方法的参数和返回值。如此就有了编译时检查。
 */
typedef String DEF(int i, String s);
String fun2(DEF def) {//如此就有编译时检查了
  return def(1, "参数");
}
//fun3方法表示的含义与fun2一致,只是fun2使用了typedef关键字,更加简洁
String fun3(String method(int i, String s)) {
  return method(1, "参数");
}
使用场景

在点击事件、接口回调等场景中使用

//定义click方法类型;
typedef void onClick();
class Button {
  //对外暴露设置点击事件方法,把点击后需要执行的方法传递进来
  void setOnClickListener(onClick onClickMethod) {
    onClickMethod();//调用方法
  }
}

默认值参数

可以在方法体中初始化参数默认值。如果该方法没有被传入值为null,则使用默认值

/**
 * 默认值参数,可以设置参数的默认值
 */
void fun({int i = 1, String str = "我是默认值"}) {
}
void fun([int i = 1, String str = "我是默认值"]) {
}

可选位置参数

使用“[]”包裹方法体。如果方法有多个参数,想给某个参数传值,那么该参数前的参数都要传值。只能按照顺序传值。

//调用fun方法
fun(1);
fun(1, "传递一个参数");
/**
 * 可选位置参数
 * 如果想给String str传值,那int i就必须传值
 */
void fun([int i, String str]) {
}

可选命名参数

使用“{}”包裹方法体,可以根据参数名称进行传值。调用方法时,使用“:”进行分割参数名称和传入参数,以键值对方式传入参数。

//调用fun方法,给参数名为“str”的参数赋值
fun(str:"可选位置参数");
fun(i:3);
/**
 * 可选命名参数,使用参数名称给参数赋值
 */
void fun({int i, String str}) {
}
使用场景:可以不需要像Java一样,写很多重载方法,并有默认值。

二:异常

抛出异常

Dart 异常是非检查异常。 方法无需声明了他们所抛出的异常, 调用方法时也不要求你捕获任何异常。
Dart中提供了 Exception和Error类型, 以及一些子类型。你还可以定义自己的异常类型。
Dart中可以抛出任何非null对象为异常,不仅仅是实现了 Exception 或者Error 的对象。

/**
 * 抛出异常 
 */
String test() {
  //抛出Exception
  throw new Exception("抛出Exception");
  //抛出自定义对象
  throw new MyClass();
  //抛出String
  throw "抛出String";
  //抛出int
  throw 100;
  //抛出方法
  throw testMethod();
}

捕捉异常

Dart中捕获异常同样是使用catch语句,catch()方法可以带有一个或两个参数,第一个参数为抛出的异常对象, 第二个为堆栈信息 ( StackTrace 对象)。

on关键字:Dart中的catch无法指定异常类型,需要结合on来使用。
rethrow关键字:可以把捕获的异常给重新抛出
/**
 * catch不同类型的异常
 * catch的参数:exc、exd
 * 此时catch的参数无需设置类型,参数数量也可以是1个或者2个
 */
void main() {
  try {
    test();
  } catch(exc, exd) {//catch所有类型 异常
    print(exc);//抛出的异常对象
    print(exd);//StackTrace 调用栈信息
  } on Exception catch(exc, exd) {//catch指定类型 Exception
  } on String catch(exc) {//catch指定类型 String
  } on Function catch(exc) {//catch指定类型 方法
	rethrow;//捕获的异常重新抛出
  }
}

三:类

Dart的命名规范

源文件:lowercase_with_underscores 风格来命名库和文件名。例如:my_dart_file
类名:UpperCamelCase风格来命名类名。例如:MyClass
方法名:lowerCamelCase。例如:myCustomMethod
变量、常量:lowerCamelCase。例如:myCompanyName

Dart的中的访问修饰符_

Dart中只有两种访问范围,使用下划线开头是私有属性,相当于private,Dart中只有public或private。

修饰类:_类名;
修饰方法:_方法名;
修饰变量:_变量名;

举个栗子

//公共范围(public)
public String str;//Java中
String str;//Dart中
//私有范围(private)
private String str;//Java中
String _str;//Dart中

构造方法、可选参数构造方法、命名构造方法

Dart中简化了构造方法。并且由于Dart中不支持方法重载。所以构造方法也不可以重载,由此产生了命名构造方法;

class Person {
  String name;
  String _age;
  //构造方法
  Person(this.name, this._age);
  //可选参数构造方法
  Person({String name, String age}) {
     this.name = name;
     this._age = age;
  }
  //命名构造方法,相对于可选参数构造方法,表明的含义更加清晰
  Person.name(this.name);
  Person._age(this._age);
}

参数初始化列表

​ 在构造方法的方法体执行之前会先执行初始化列表

/**
 * 在构造方法的参数体之后,方法体之前,使用冒号分割。给本类变量赋值。
 */
Person.initFromBean(Person person):name = person.name, _age = person._age;
Person.initName(String name): name = name; 
Person.initAge(int age):_age = age {}

重定向构造方法

重定向构造方法是没有方法体的,在构造方法的参数体后,使用冒号调用其他构造方法。
使用场景:例如自定义View中,构造方法自己调用自己。

//调用
View view = View.context(10);
class View {
  int context;
  int attr;
  int style;
  //重定向调用,命名构造方法View.attr
  View.context(int context):this.attr(context, 666);
  //重定向调用,构造方法View
  View.attr(int context, int attr):this(context, attr, 234);
  //构造方法
  View(this.context, this.attr, this.style);
}

常量构造方法

使用const关键字修饰构造方法,并且所有全局变量声明为final。
使用const关键字来创建对象,当你创建时传入的参数一样,无论你创建几个对象,它们其实都是同一个对象。

class Demo {
  final int width;
  final int height;
  /**
   * 常量构造方法
   */
  const Demo(this.width, this.height);
}
void main() {
  //使用new来创建,常量构造方法的对象和普通对象没有区别
  Demo demo1 = new Demo(1, 1);
  Demo demo2 = new Demo(1, 1);
  print(demo1 == demo2);//false
  print(demo1.hashCode == demo2.hashCode);//false
  /**
   * 使用const来创建对象,传递的参数一样,对象必须有常量构造方法
   * 代表它们是同一个编译期常量对象。
   */
  Demo demo3 = const Demo(1, 1);
  Demo demo4 = const Demo(1, 1);
  print(demo3 == demo4);//true
  print(demo3.hashCode == demo4.hashCode);//true
}

工厂构造方法

使用factory关键词修饰的构造方法时,这个构造方法必须返回,类的实例或者子类的实例。但是可以不创建新的实例。
例如:工厂构造函数可能从缓存中获取一个实例并返回,或者返回一个子类型的实例。(工厂构造函数无法访问 this)

/**
 * static和factory修饰构造方法产生的效果差不多。
 * 但是他们的本质是不一样的,factory修饰属于构造方法,必须返回类或子类的实例对象,
 * 而static修饰则是方法,如果不指明返回值是可以不返回实例对象的。
 */
class Parent {
  //构造方法
  Parent();
  /**
   * 工厂构造方法
   * 使用factory关键字修饰一个命名构造方法
   * 返回一个子类实例
   */
  factory Parent.getChild() {
    return new Child();
  }
  /**
   * 静态方法
   * 返回一个子类实例
   */
  static Child getChild1() {
    return new Child();
  }
}
工厂构造方法写单例
//调用
SingleInstance instance = SingleInstance.getInstance();
/**
 * Dart单例
 */
class SingleInstance{
  static SingleInstance _instance;
  /**
   * 命名构造方法 + 私有化
   */
  SingleInstance._newInstance();
  /**
   * 工厂构造方法 + 命名构造放,返回对象单例
   */
  factory SingleInstance.getInstance() {
    if(_instance == null) {
      //调用 私有命名构造方法 创建对象
      _instance = new SingleInstance._newInstance();
    }
    //返回单例实例
    return _instance;
  }
  String getString() {
    return "我是返回值";
  }
}

get、set方法

实例对象的非私有属性变量(非final、非私有),都会有一个隐式的get\set方法,无需写get\set方法。

View view = new View();
view.height = 1000;//set赋值
int height = view.height;//get获取

class View {
  //实例对象的非私有属性变量,会有一个隐式的get\set方法,无需写get\set方法
  int place;
  int _width;
  int _height;

  int get width => _width;
  set width(int value) {
    _width = value;
  }
  int get height => _height;
  set height(int value) => _height = value;
}

运算符重载

使用operator关键字,可以把已有操作符进行重新定义,可重载的运算符有:
在这里插入图片描述

/**
 * 使用重新定义的>操作符,来比较view1和view2两个对象,传入的参数面积大小。返回bool类型
 */
bool b = view1 > view2;

class View {
  int _width;
  int _height;
  
  int get width => _width;
  set width(int value) {
    _width = value;
  }
  int get height => _height;
  set height(int value) => _height = value;
  //重新定义 >操作符,比较两个View的面积
  bool operator>(View otherView) {
    bool b =  height * width > otherView.height * otherView.width;
    return b;
  }
}

抽象类

使用 abstract 修饰符定义一个抽象类。抽象类中允许出现无方法体的方法

/**
 * abstract 声明抽象类
 */
abstract class Person{
  String name;
  void play();//抽象方法,不需要在方法前声明abstract,可以没有方法体
  void sleep() {}//也可以有正常的方法
  Person(this.name);//父类构造方法
}
//extends 继承抽象类
class Child1 extends Person {
  Child1(String name) : super(name);//子类构造
  @override
  void play() {//实现抽象方法
  }
}
class Child2 extends Person {
  Child2(String name) : super(name);//子类构造
  @override
  void play() {//实现抽象方法
  }
  @override
  void sleep() {//重写父类方法
    super.sleep();//使用super调用父类sleep方法
  }
}

接口

Dart中没有interface关键字。在Dart的类中,都隐式的定义了一个包含所有实例成员的接口。
使用implements关键字,可以实现这个类的所有实例成员。不能实现抽象类
(Dart中的类,即可以是类,也可以是接口。分不清了🤣🤣🤣🤣)

class Listener{
  static String name;
  String _age;

  static Function onLongClick() {//静态方法
  }
  void onClick(){//普通方法
  }
}
/**
 * 使用implements实现接口
 */
class MyInterface implements Listener {
  @override
  void onClick() {//实现普通方法
  }
  @override
  String _age;
}

接口与继承的区别

1、单继承,多实现。
2、继承可以有选择的重写父类方法并且可以使用super,实现强制重新定义接口所有成员。

可调用的类

如果Dart 类实现了call()方法,在对象实例后加括号,可以直接调用到call()方法。如果没有实现call方法则会报错。

CallDemo myCall = new CallDemo();
String str = myCall("我是字符串");//myCall对象后加括号,调用call方法;

class CallDemo {
  String str;
  String call(String str) {
    this.str = str;
    return this.str;
  }
}

混合mixins

Mixins 是一种在多类继承中,重用一个类代码的方法。
使用with关键字,后面跟着需要混入的类。要注意的是,被混入的类不能有构造方法。
混入与继承是兼容的,可以同时使用extendswith关键字。同时也可以使用super关键字,来调用被混入的方法和继承的方法。
混入方法时,如果存在重复的方法。
1、优先调用自身的方法
2、如果自身没有对应方法,就从with最右边开始查找。

C c = new C();
c.a();//c类中混入了A类,所以可以调用a方法
c.b();//c类中混入了B类,所以可以调用b方法
c.c();//调用自身的c方法
class A {
  void a() {//被混入的方法a
    print("a~~~~~~~");
  }
}
class B {
  void b() {//被混入的方法b
    print("b~~~~~~~");
  }
}
abstract class D {//抽象方法
  void d() {
  }
  //void e();//也可以混入抽象方法,这里为了记录super关键字,就不演示了
}
/**
 * 继承D类
 * 混入B、A类
 */
class C extends D with B, A{
  @override
  void d() {//重写父类D的d方法
    super.d();//调用父类D的d方法
  }
  void c() {
    super.a();//调用被混入的方法a
    print("c~~~~~~~");
  }
}

总结:
mixins弥补了接口和继承的不足,继承只能单继承,而接口无法复用实现,mixins却可以多混入并且能利用到混入类的具体实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值