Skip to content

Dart教程 - 7 面向对象(2)

继续讲解面向对象...

7.3 继承

在现实世界,有麻雀和鸽子,它们都属于鸟类,麻雀、鸽子和鸟类的关系是父类和子类的关系。

麻雀和鸽子都会飞,我们可以在麻雀类中定义一个飞的方法,在鸽子类中定义一个飞的方法,但是这两个飞的方法是一样的,都是用翅膀飞。我们可以在鸟类中定义一个飞的方法,让麻雀和鸽子类都继承这个鸟类,那么它们就拥有了飞的方法,就不用再定义了。

1 继承的语法

在Dart中,使用extends关键字实现继承。

dart
class 子类名 extends 父类名 {
  	类内容
}

举个栗子:

麻雀继承鸟类,鸽子继承鸟类:

dart
class Bird {
  // 定义一个鸟类
  late int age; // 鸟都有年龄

  void fly() {
    // 定义了一个飞的方法
    print("我${this.age}岁了,我会飞");
  }

  void tweet() {
    // 定义了一个叫的方法
    print("我会叫");
  }
}

class Sparrow extends Bird {
  // 定义一个麻雀类,继承自鸟类
}

class Pigeon extends Bird {
  // 定义一个鸽子类,继承自鸟类
}

void main() {
  Sparrow sparrow = Sparrow(); // 创建一个麻雀对象
  sparrow.age = 1;
  sparrow.fly();
  sparrow.tweet();

  Pigeon pigeon = Pigeon(); // 创建一个鸽子对象
  pigeon.age = 2;
  pigeon.fly();
  pigeon.tweet();
}

在上面的代码中,我们先定义了一个鸟类,然后在鸟类中定义了 age属性 ,并定义了两个方法 fly方法tweet方法

然后定义类麻雀类,继承鸟类,那么就拥有了鸟类的属性和方法。鸽子类也同样。

执行结果:

我1岁了,我会飞
我会叫
我2岁了,我会飞
我会叫

注意,继承不能继承父类私有的成员变量和方法。

如果父类的成员变量和属性不想被子类继承,可以设置为私有成员。

一个类如果没有写明继承哪个类,那么默认都是集成自Object类,所以最终的结果就是Object类是所有类的父类!

2 复写父类方法

所以继承父类就拥有了父类非私有的成员变量和方法,如果父类不是我想要的方法,我还可以进行覆盖。

例如,鸟类提供了叫的方法,但是我麻雀有自己的叫法,我要啾啾叫,那么我们可以重写父类的方法,实现自己的个性化。

dart
class Bird {
  // 定义一个鸟类
  late int age; // 鸟都有年龄

  void fly() {
    // 定义了一个飞的方法
    print("我${this.age}岁了,我会飞");
  }

  void tweet() {
    // 定义了一个叫的方法
    print("我会叫");
  }
}

class Sparrow extends Bird {
  // 定义一个麻雀类,继承自鸟类
  void tweet() {
    print("我会啾啾叫");
  }
}

class Pigeon extends Bird {
  // 定义一个鸽子类,继承自鸟类
}

void main() {
  Sparrow sparrow = Sparrow(); // 创建一个麻雀对象
  sparrow.age = 1;
  sparrow.fly();
  sparrow.tweet();

  Pigeon pigeon = Pigeon(); // 创建一个鸽子对象
  pigeon.age = 2;
  pigeon.fly();
  pigeon.tweet();
}

执行结果:

我1岁了,我会飞
我会啾啾叫
我2岁了,我会飞
我会叫

那么如果我在父类的fly()方法中调用tweet()方法,然后子类方法调用fly()方法,那么会如何执行呢?

dart
class Bird {
  void fly() {
    // 定义了一个飞的方法
    print("我会飞");

    tweet();
  }

  void tweet() {
    // 定义了一个叫的方法
    print("我会叫");
  }
}

class Sparrow extends Bird {
  void tweet() {
    print("我会啾啾叫");
  }
}

void main() {
  Sparrow sparrow = Sparrow(); // 创建一个麻雀对象
  sparrow.fly();
}

sparrow.fly() 调用的是继承自父类的方法,在 fly() 方法中调用了 tweet() 方法,那么调用的是父类的tweet() 方法还是子类的tweet() 方法呢?

是调用子类的方法。

执行结果:

我会飞
我会啾啾叫

3 调用父类方法

我们在重写父类方法的时候,应该尽量做到在父类方法的基础上进行扩展。

所以很有可能需要调用父类被重写的方法,然后在父类原来的方法上进行扩展。

那么如果我们想要在子类中调用父类被重写的属性和方法呢?

使用 super 关键字来调用父类的属性或方法。

举个栗子:

dart
class Bird {
  // 定义一个鸟类
  int age = 1; // 鸟都有年龄

  void fly() {
    // 定义了一个飞的方法
    print("我${this.age}岁了,我会飞");
  }

  void tweet() {
    // 定义了一个叫的方法
    print("我会叫");
  }
}

class Pigeon extends Bird {
  late int age;
  // 定义一个鸽子类,继承自鸟类
  void tweet() {
    // 重写了父类叫的方法
    print("我会咕咕叫");
  }

  void test() {
    print("age:${super.age}"); // 调用父类的属性
    super.tweet(); // 调用父类的方法

    print("age:${this.age}");
    this.tweet();
  }
}

void main() {
  Pigeon pigeon = Pigeon(); // 创建一个鸽子对象
  pigeon.age = 10;
  pigeon.test();
}

上面子类中定义了一个和父类中相同名称的属性age,如果要在子类中调用父类的属性 ,可以通过 super.父类属性 来调用,同样,如果要在子类中调用父类的方法,可以通过 super.父类方法() 来调用。

执行结果:

age:1
我会叫
age:10
我会咕咕叫

4 构造函数的继承

子类继承父类,是没办法直接继承构造函数的。

但是子类的构造函数是会隐式的调用的无参构造函数。

举个栗子:

dart
class Bird {
  late int age;

  Bird() {
    print("执行了 Bird 构造函数");
  }
}

class Pigeon extends Bird {
  Pigeon() {
    print("执行了 Pigeon 构造函数");
  }

  Pigeon.fromName(String name) {
    print("执行了 fromName 明明构造函数");
  }
}

void main() {
  Pigeon(); // 创建对象,没有传入参数
  Pigeon.fromName("DouBi");
}

执行结果:

执行了 Bird 构造函数 执行了 Pigeon 构造函数 执行了 Bird 构造函数 执行了 fromName 明明构造函数

通过结果可以看到,子类的构造函数会先调用父类的无参构造函数。

如果父类定义了有参的构造函数,那么就没有无参的构造函数了,那么就会报错。

举个栗子:

dart
class Bird {
  late int age;

  Bird(this.age); // 定义了有参的构造函数
}

class Pigeon extends Bird {}

上面的代码是会报错的,因为Pigeon类没有写构造函数,使用的是无参构造函数,执行的时候会调用父类Bird的无参构造函数,但是Bird类没有无参构造函数,所以会报错。

所以我们在写Pigeon类的构造函数的时候,要显式的调用父类的构造函数。

调用父类的构造函数需要在构造函数的初始化列表中使用super()来调用:

dart
class Bird {
  late int age;

  Bird(this.age); // 定义了有参的构造函数
}

class Pigeon extends Bird {
  Pigeon(int age) : super(age);		// 使用super调用父类的构造函数
}

我们还可以调用父类的命名构造函数:

dart
class Bird {
  late int age;

  Bird(this.age);

  Bird.fromMap(Map<String, Object> map) : this.age = map['age'] as int;
}

class Pigeon extends Bird {
  Pigeon(int age) : super(age);		// 使用super调用父类的构造函数

  // 调用父类的命名构造函数
  Pigeon.fromMap(Map<String, Object> map) : super.fromMap(map) {
  }
}

5 类型判断

我们可以判断某个对象的类型,以及是否是某个对象的实例。

首先有如下代码:

dart
class Bird {
  // 鸟类
}

class Sparrow extends Bird {
  // 麻雀类,继承自鸟类
}

class Pigeon extends Bird {
  // 鸽子类,继承自鸟类
}

runtimeType属性

dart中,可以使用 runtimeType 判断某个对象是否是某个类型,注意:子类的对象不是父类的对象的类型。

举个栗子,基于上面的代码:

dart
void main() {
  Pigeon pigeon = Pigeon();
  Sparrow sparrow = Sparrow();

  print(pigeon.runtimeType); // 输出: Pigeon
  print(sparrow.runtimeType); // 输出: Sparrow

  print(pigeon.runtimeType == Pigeon); // true,鸽子对象的类型是鸽子
  print(pigeon.runtimeType == Bird); // false,鸽子对象的类型不是鸟
  print(sparrow.runtimeType == Sparrow); // true,麻雀对象的类型是麻雀
}

is 关键字

is 关键字可以判断某个对象是否是某个类型的实例,子类对象也是父类对象的实例。

举个例子,基于上面的代码:

dart
void main() {
  Pigeon pigeon = Pigeon();

  print(pigeon is Pigeon); // true,鸽子对象是鸽子类型的实例
  print(pigeon is Bird); // true,鸽子对象是鸟类的实例
  print(pigeon is Sparrow); // false,鸽子对象不是麻雀类的实例
}

6 Mixins

我现在是一只鸡,我也想继承鸟类,但是我是家禽,我还想继承家禽类。

那么就需要用到多继承。

在C++、Python中是支持多继承的,但是在Dart中是不支持多继承的。

在Dart中,新增了一种复用代码的机制Mixins,中文意思是混入,允许你在类中重用其他类的代码,而无需继承这些类。它提供了一种灵活的方式来组合和共享功能,以实现代码重用和组合。

在Dart中,有两种方式可以定义Mixin:使用关键字mixin定义Mixin和使用 class 定义一个类。

举个栗子:

下面使用 class 定义了一个家禽类

dart
class Bird {
  // 定义一个鸟类
  late int age; // 鸟都有年龄

  void fly() {
    // 定义了一个飞的方法
    print("我${this.age}岁了,我会飞");
  }
}

class Poultry {
  // 定义一个家禽类
  late int number; // 家禽需要编号

  void eat() {
    // 定义了一个吃的方法
    print("我吃饭啦");
  }
}

class Chicken extends Bird with Poultry {
  // 定义一个鸡类,继承自鸟类和家禽类

  void fly() {
    print("我不会飞");
  }
}

void main() {
  Chicken chicken = Chicken(); // 创建一个鸡对象
  chicken.age = 1;
  chicken.number = 9527;
  chicken.fly();
  chicken.eat();
}

然后我们在 Chicken 类上继承了Bird 类,然后使用 with 关键字将 Poultry 家禽类混入到Chicken 类中。

这样就 Chicken 类就可以访问和使用Poultry 家禽类中的属性和方法。

上面定义 Poultry 家禽类,还可以使用关键字mixin 来定义:

dart
mixin Poultry {
  // 定义一个家禽类
  late int number; // 家禽需要编号

  void eat() {
    // 定义了一个吃的方法
    print("我吃饭啦");
  }
}

那么使用 class 关键字和使用 mixin 关键字定义混入有什么区别呢?

使用mixin关键字定义Mixin:Mixin类不能直接被实例化,而是通过混入到其他类中来复用其方法和属性。这意味着Mixin类不能有构造函数,并且不能作为独立的类来使用。使用mixin关键字定义Mixin可以更明确地表达其用途(就是用来被混入的),而使用class关键字定义Mixin则与普通类的定义方式更一致。另外,mixin类只能继承自Object,不能继承其他类。

在使用的时候,一个类是可以混入多个类的。如果混入的多个类中存在相同的属性或方法,那么哪一个类中的方法生效呢?

当一个类混入多个类并且这些混入类中存在相同属性或方法时,方法解析的顺序遵循"最后声明的优先"原则。也就是说,最后一个混入的类中的方法将覆盖之前混入的类中的属性和方法。

举个栗子:

dart
mixin A {
  int value = 1;
  void foo() {
    print('A foo');
  }
}

mixin B {
  int value = 2;
  void foo() {
    print('B foo');
  }
}

class C with A, B {
  void test() {
    foo(); // 解析为 B 中的 foo 方法
  }

  void testValue() {
    print(value);
  }
}

void main() {
  var c = C();
  c.test(); // 输出: B foo
  c.testValue(); // 输出: 2
}

在上面的示例中,我们定义了两个Mixin类:AB,它们都包含一个名为foo的方法。然后,我们创建了一个名为C的类,使用with关键字将AB混入到C中。

C类中的test方法中调用了foo方法。由于B是最后一个混入的类,所以方法解析的顺序从右到左,即先在B中查找同名方法。因此,最终调用的是B中的foo方法,输出结果为"B foo"。

同样的,打印value属性,打印的是后混入的B类中的属性。

7.4 多态

1 什么是多态

多态就是多种状态,同一个类型的父类型对象,因为指向的是不同的子对象,而表现出的不同的状态。

所以多态是建立在继承的基础之上的。

举个栗子:

dart
class Bird {
  void tweet() {}
}

class Sparrow extends Bird {
  void tweet() {
    print("我会啾啾叫");
  }
}

class Pigeon extends Bird {
  void tweet() {
    print("我会咕咕叫");
  }
}

void main() {
  Bird bird1 = Sparrow(); // 创建一个麻雀对象
  Bird bird2 = Pigeon(); // 创建一个鸽子对象

  bird1.tweet();
  bird2.tweet();
}

上面麻雀类和鸽子类都继承自鸟类,然后创建了一个麻雀对象和鸽子对象,都赋给了鸟类,通过两个对象分别调用tweet()方法。

执行结果:

我会啾啾叫
我会咕咕叫

虽然两个都是鸟类的变量,执行的都是tweet()方法,但是因为是不同的子类对象,却得到不同的结果。

以父类做定义声明,以子类做实际的工作,用于获取同一个行为的不同状态,这就是多态。

那也没看出多态有什么用啊。

多态的作用:

  • 提高代码的维护性
  • 提高代码的扩展性
  • 把不同的子类对象当做父类来看待,可以屏蔽不同子类对象之间的差异,写出通用的代码,以适应需求的不断变化。

2 多态的使用

说了那么多,有点虚,举个栗子:

实现一个功能:学生做交通工具去某个地方,交通工具可能是汽车、飞机。

先定一个汽车类:

传入一个目的地,就可以开车去了。

dart
class Car {
  void run(String destination) {
    print("开车去->${destination}");
  }
}

再定义一个飞机类:

dart
class Plane {
  void fly(String destination) {
    print("飞去->${destination}");
  }
}

然后定义一个学生类:

dart
class Student {
  void go_to(var vehicle, String destination) {	// 传入交通工具
    if (vehicle.runtimeType == Car) {			// 判断交通工具的类型,然后调用交通工具的方法
      vehicle.run(destination);
    } else if (vehicle.runtimeType == Plane) {
      vehicle.fly(destination);
    }
  }
}

学生类有一个go_to()方法,接收交通工具和目的地,然后在方法中判断交通工具的类型,然后调用交通工具的方法。

调用代码:

dart
void main(List<String> args) {
  Student stu = Student();
  Car car = Car();
  Plane plane = Plane();
  stu.go_to(car, "北京");
  stu.go_to(plane, "新疆");
}

执行结果:

开车去->北京
飞去->新疆

上面的代码可以实现功能,但是不易于扩展,如果我们现在增加一个交通工具火车,则还需要修改Student类的go_to()方法,针对新的交通工具来处理,因为学生类和汽车、飞机类直接存在依赖关系,耦合性高。

这样是违反了设计原则中的开闭原则,对扩展是开放的,对修改是封闭的,也就是允许在不改变它代码的前提下变更它的行为。

所以上面的代码扩展性就比较差了,那么怎么来优化代码,降低代码的耦合性呢?

这就需要用到多态了。

首先定义一个父类Vehicle(交通工具类),并定义一个transport()方法,都是交通工具,都是运输功能嘛。

然后让Car类和Plane类都继承这个父类,因为不同的子类运输方式不一样,所以子类需要重写父类的方法,实现自己的功能。

dart
class Vehicle {
  void transport(String destination) {}
}

class Car extends Vehicle {
  void transport(String destination) {
    print("开车去->${destination}");
  }
}

class Plane extends Vehicle {
  void transport(String destination) {
    print("飞去->${destination}");
  }
}

然后修改学生类:

dart
class Student {
  void go_to(Vehicle vehicle, String destination) {
    vehicle.transport(destination);
  }
}

学生类只需要调用交通工具的运输功能就可以了。

调用的代码不变:

dart
void main(List<String> args) {
  Student stu = Student();
  Car car = Car();
  Plane plane = Plane();
  stu.go_to(car, "北京");
  stu.go_to(plane, "新疆");
}

执行结果:

开车去->北京
飞去->新疆

上面的代码使用了多态,学生类与各个交通工具子类已经不直接产生关系,遵从了设置原则中的依赖倒置原则(程序依赖于抽象接口,不要依赖于具体实现)。

此时如果新增一个火车的交通工具,不用再修改学生类的代码,代码耦合性大大降低。

3 抽象类

什么是抽象类?

含有抽象方法的类成为抽象类。

那什么是抽象方法?

抽象方法就是没有方法体,方法体为空的方法。

上面的 Vehicle 类中的 transport 方法,没有方法体,我们可以将它定义为一个抽象方法,将 Vehicle 定义为抽象类 。

class 前面加上 abstract 关键字,就是定义了抽象类。

dart
abstract class Vehicle {
  void transport(destination);
}

抽象类中也可以包含非抽象方法,子类继承抽象类需要实现(重写)抽象类中所有的抽象方法。

抽象类有什么作用呢?

抽象类是不能被实例化的,也就是不能用来创建对象。一般抽象类都是作为父类使用的,父类用来确定有哪些方法,相当于用来确定设计的标准,用于对子类的约束。

子类用来实现父类的标准,负责具体的实现,配合多态使用,获得不同的工作状态。

4 接口

如果一个抽象类中的方法都是抽象方法,我们可以将这个抽象类定义成接口。

在Java中,定义接口使用 interface 关键字,和定义抽象类是不同的。但是在Dart中,并没有专门的关键字来定义接口。在Dart 中的接口就是通过类来实现的。所以一个抽象类是接口还是抽象来要看怎么使用,通过 extends 来继承就是抽象类,通过 implements 来实现就是接口

举个栗子:

dart
// 定义一个抽象类
abstract class Bird {
  void tweet();
}

// 定义一个接口
abstract class Animal {
  void breathe();
}

// 定义一个接口
abstract class Helpful {
  void help();
}

class Sparrow extends Bird implements Animal, Helpful {
  @override
  void breathe() {
    print("我要呼吸");
  }

  @override
  void tweet() {
    print("我会啾啾叫");
  }

  @override
  void help() {
    print("有益的");
  }
}

void main() {
  Animal animal = Sparrow();
  animal.breathe();
}

上面我们定义了一个抽象类 Bird ,和两个接口 AnimalHelpful

然后定义了一个 Sparrow 类作为子类继承 Bird 类,同时实现了 AnimalHelpful两个接口。此时才看出抽象类和接口的不同,也就是说接口的定义是隐式的。

一个类只能有一个父类,但是可以有多个接口。一个类需要实现抽象类和接口中所有的抽象方法,否则编译会报错。

接口中只能定义常量和抽象方法,所以抽象类的作用主要是提供约束和规范。

结合前面多态的使用去理解,前面多态的使用中,使用的是父类来完成的,我们也可以使用接口来完成。

代码:

dart
abstract class Vehicle {				// 定义交通工具的接口,所有的交通工具都需要实现该接口
  void transport(String destination);
}

class Car implements Vehicle {    // 需要实现交通工具接口
  void transport(String destination) {
    print("开车去->${destination}");
  }
}

class Plane implements Vehicle {	// 需要实现交通工具接口
  void transport(String destination) {
    print("飞去->${destination}");
  }
}

class Student {
  void go_to(Vehicle vehicle, String destination) {		// 传入的参数是交通工具,交通工具都必须有transport()方法
    vehicle.transport(destination);
  }
}

void main(List<String> args) {
  Student stu = Student();
  Car car = Car();
  Plane plane = Plane();
  stu.go_to(car, "北京");
  stu.go_to(plane, "新疆");
}

7.5 类与类的关系

类与类有以下几种关系:

泛化

子类与父类的关系,B类泛化A类,B类是A类的一种。

场景:B类继承A类。

关联

部分与整体的关系,A与B关联,B是A的一部分。

场景:在A类中包含B类型的属性。

依赖

合作关系,A类依赖B类,A的某些功能需要靠B类实现。

场景:B类型作为A类中方法的参数,并不是A的成员。

7.6 数据与JSON的转换

1 JSON 简介

什么是JSON?

JSON就是特定格式的字符串。我们可以将数据按照这个格式进行封装,然后可以在不同的语言和系统之间进行传送和交互。

JSON的2种格式:

格式一:

是一个对象格式的结构。{} 括起来,其中是属性。

json
{
    key1:value1,
    key2:value2,
    ...
}

举个栗子,以下是一个学生信息的JSON格式,和Python中的字典格式是一样的:

json
{
	"sid": "001",
	"name": "zhangsan",
	"age": 18
}

格式二:

外部是一个列表格式的结构,内部是一个个的对象格式的数据。

json
[
    {
        key1:value1,
        key2:value2 
    },
    {
         key3:value3,
         key4:value4   
    }
]

举个栗子,以下是一个学生信息的列表

json
[{
		"sid": "S001",
		"name": "zhangsan",
		"age": 18
	},
	{
		"sid": "S002",
		"name": "lisi",
		"age": 19
	},
	{
		"sid": "S003",
		"name": "wangwu",
		"age": 17
	}
]

JSON格式是可以相互嵌套的,属性中可以再嵌套JSON。

2 字典转JSON

  • 使用 jsonEncode() 函数将字典转换为 JSON 字符串。

举个栗子:

需要引入 dart:convert 包。

dart
import 'dart:convert';

void main() {
  Map<String, dynamic> data = {
    'name': '逗比',
    'age': 25,
  };

  String jsonString = jsonEncode(data);
  print(jsonString);
}

执行结果:

{"name":"逗比","age":25}

3 JSON转字典

  • 使用 jsonDecode() 函数将 JSON 字符串解析为 Dart 中的字典(Map)。
  • 返回的对象类型为 Map<String, dynamic>

举个栗子:

dart
import 'dart:convert';

void main() {
  String jsonString = '{"name": "逗比", "age": 25}';
  Map<String, dynamic> data = jsonDecode(jsonString);

  print(data['name']);
  print(data['age']);
}

执行结果:

逗比
25

4 对象转JSON

举个栗子:

dart
import 'dart:convert';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'age': age,
    };
  }
}

void main() {
  Person person = Person('逗比', 25);
  String jsonString = jsonEncode(person.toJson());

  print(jsonString);
}

我们需要先获取对象的字典格式的数据,所以在对象中定义了一个toJson()方法,返回字典数据,然后再通过jsonEncode()函数,将字典转换为JSON字符串:

5 JSON转对象

举个栗子:

dart
import 'dart:convert';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(json['name'], json['age']);
  }
}

void main() {
  String jsonString = '{"name": "逗比", "age": 25}';

  // 先将Json 转换为字典
  Map<String, dynamic> data = jsonDecode(jsonString);
  // 使用工厂构造函数将字典转换为对象
  Person person = Person.fromJson(data);

  print(person.name);
  print(person.age);
}

一般将JSON转换为字典就可以获取到数据了,如果有特殊的需求,再将字典转换为对象。

首先将JSON字符串转换为字典,然后通过工厂构造函数通过字典构建对象。

执行结果:

逗比
25

6 列表转JSON

简单数据格式的列表转换为JSON

举个栗子:

dart
import 'dart:convert';

void main() {
  List<String> names = ['逗比', '二比', '牛比'];
  String jsonString = jsonEncode(names);
  print(jsonString);
}

直接调用 jsonEncode() 函数进行转换即可。

执行结果:

["逗比","二比","牛比"]

如果是对象列表呢?

对象列表转换为JSON

也是调用 jsonEncode() 函数,直接传入列表对象,jsonEncode() 函数会自动调用对象的 toJson() 方法,如果类中没有定义 toJson() 会报错。

举个栗子:

dart
import 'dart:convert';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'age': age,
    };
  }
}

void main() {
  List<Person> personList = [];
  personList.add(Person("逗比", 12));
  personList.add(Person("二比", 13));
  personList.add(Person("牛比", 14));

  String jsonString = jsonEncode(personList);
  print(jsonString);
}

7 JSON转列表

简单数据格式的JSON转列表

举个栗子:

dart
import 'dart:convert';


void main() {
  String jsonString = '["逗比", "二比", "牛比"]';

  List<dynamic> myList = jsonDecode(jsonString);
  print(myList); // 输出:[逗比, 二比, 牛比]
}

直接调用 jsonDecode() 方法转换为 List<dynamic>

JSON转换为对象列表

举个栗子:

dart
import 'dart:convert';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(json['name'], json['age']);
  }
}

void main() {
  String jsonString = '[{"name":"逗比","age":12},{"name":"二比","age":13},{"name":"牛比","age":14}]';

  // 首先将JSON转换为List<dynamic>
  List<dynamic> jsonDynamicList = jsonDecode(jsonString);

  // 然后遍历List<dynamic> 将其中的元素分别转换为Person对象
  List<Person> personList =
      jsonDynamicList.map((json) => Person.fromJson(json)).toList();

  for (var person in personList) {
    print('Name: ${person.name}, Age: ${person.age}');
  }
}

首先还是需要在类中定义工厂构造函数。

然后在转换的时候,先将JSON转换为 List<dynamic> 列表,这个时候列表中的元素是一个个Map类型的字段元素。所以需要遍历 List<dynamic> ,将其中的字典元素转换为 Person 对象,上面使用的是map 函数。

所以一个类如果要与JSON字符串实现相互转换,需要实现 toJson()方法 和 通过字典转换为对象的工厂构造方法。