【Flutter】Dart 泛型 ( 泛型类 | 泛型方法 | 特定类型约束的泛型 )

2023-03-28 21:17:24 浏览数 (2)

文章目录

  • 一、Dart 泛型类与泛型方法
  • 二、Dart 泛型中的特定类型约束
  • 三、Dart 自带泛型
  • 四、完整代码示例
  • 五、 相关资源

一、Dart 泛型类与泛型方法


泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型 ;

泛型类 : 提高代码复用程度 ;

泛型方法 : 参数或返回值有泛型类型约束 , 参数或返回值类型必须符合对应的泛型类型 , 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错 ;

泛型类示例 :

代码语言:javascript复制
/// 泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型
///
/// 泛型类 : 提高代码复用程度
/// 该类是一个缓存类 , 缓存的数据类型是 T 泛型 , 该类型可以是任意类型
class Cache<T>{
  /// 缓存数据存储到该 Map 集合中
  Map<String, Object> _map = Map();

  /// 设置泛型缓存数据 , 该方法是泛型方法
  /// 此处将 T 类型的数据存放到 map 集合中
  void setCacheItem(String key, T value){
    _map[key] = value;
  }

  /// 取出泛型缓存数据 , 该方法是泛型方法
  T getCachedItem(String key){
    return _map[key];
  }
}

测试上述泛型类 :

代码语言:javascript复制
/// 泛型测试类
class Generic{

  /// 该方法测试泛型类及泛型方法
  void test(){
    // 创建泛型类对象 , 泛型类型设置为 String 类型
    Cache<String> cache = Cache();
    // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
    // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
    cache.setCacheItem("name", "Tom");

    // 获取缓存内容
    String value = cache.getCachedItem("name");
    print("泛型测试, 类型字符串, 获取的缓存内容为 ${value}");


    // 创建泛型类对象 , 泛型类型设置为 int 类型
    Cache<int> cache2 = Cache();
    // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
    // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
    cache2.setCacheItem("age", 18);

    // 获取缓存内容
    int value2 = cache2.getCachedItem("age");
    print("泛型测试, 类型整型, 获取的缓存内容为 ${value2}");
  }

}

打印结果 :

代码语言:javascript复制
I/flutter (24673): 泛型测试, 类型字符串, 获取的缓存内容为 Tom
I/flutter (24673): 泛型测试, 类型整型, 获取的缓存内容为 18

二、Dart 泛型中的特定类型约束


泛型还可以进行特定类型约束 , 如指定该泛型类型必须是某个类的子类 , 使用 <T extends Person> 约束该泛型必须是某个类的子类 ;

泛型类示例代码 :

代码语言:javascript复制
/// 泛型中的特定类型约束
/// 将泛型约束为某个类型的子类
class Member<T extends Person>{
  T _person;

  /// 构造函数中设置 T _person 成员的值
  Member(this._person);

  /// 获取 _person 的名字
  String getName(){
    return _person.name;
  }
}

上述涉及到的两个类在 【Flutter】Dart 面向对象 ( 命名构造方法 | 工厂构造方法 | 命名工厂构造方法 ) 中定义 ;

测试上述泛型类 :

代码语言:javascript复制
    /// 泛型类测试
    /// 类泛型要求是 T extends Person , 泛型类型必须是 Person 的子类
    /// Student 是 Person 的子类
    Member<Student> member = Member(Student(6, "Tom", 18));
    String name = member.getName();
    print("泛型类测试, 获取的 T extends Person 泛型的 name 字段为 ${name}");

测试打印结果 :

代码语言:javascript复制
I/flutter (24673): 泛型类测试, 获取的 T extends Person 泛型的 name 字段为 Tom

三、Dart 自带泛型


在 Flutter 的 main.dart 中的 State 就是泛型类 ;

代码语言:javascript复制
class _MyHomePageState extends State<MyHomePage> {
}

State 类中要求一个泛型 T , 该泛型类型必须继承 StatefulWidget 类 ;

代码语言:javascript复制
abstract class State<T extends StatefulWidget> extends Diagnosticable {
}

此处的 MyHomePage 就是 泛型类型 , 是 StatefulWidget 类的子类 , 符合 泛型要求 ;

四、完整代码示例


泛型类 , 泛型方法 , 泛型测试相关代码 :

代码语言:javascript复制
import 'package:flutterapphello/Dart_OOP.dart';

/// 泛型测试类
class Generic{

  /// 该方法测试泛型类及泛型方法
  void test(){
    // 创建泛型类对象 , 泛型类型设置为 String 类型
    Cache<String> cache = Cache();
    // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
    // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
    cache.setCacheItem("name", "Tom");

    // 获取缓存内容
    String value = cache.getCachedItem("name");
    print("泛型测试, 类型字符串, 获取的缓存内容为 ${value}");


    // 创建泛型类对象 , 泛型类型设置为 int 类型
    Cache<int> cache2 = Cache();
    // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
    // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
    cache2.setCacheItem("age", 18);

    // 获取缓存内容
    int value2 = cache2.getCachedItem("age");
    print("泛型测试, 类型整型, 获取的缓存内容为 ${value2}");
    
    
    /// 泛型类测试
    /// 类泛型要求是 T extends Person , 泛型类型必须是 Person 的子类
    /// Student 是 Person 的子类
    Member<Student> member = Member(Student(6, "Tom", 18));
    String name = member.getName();
    print("泛型类测试, 获取的 T extends Person 泛型的 name 字段为 ${name}");

  }

}

/// 泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型
///
/// 泛型类 : 提高代码复用程度
/// 该类是一个缓存类 , 缓存的数据类型是 T 泛型 , 该类型可以是任意类型
class Cache<T>{
  /// 缓存数据存储到该 Map 集合中
  Map<String, Object> _map = Map();

  /// 设置泛型缓存数据 , 该方法是泛型方法
  /// 此处将 T 类型的数据存放到 map 集合中
  void setCacheItem(String key, T value){
    _map[key] = value;
  }

  /// 取出泛型缓存数据 , 该方法是泛型方法
  T getCachedItem(String key){
    return _map[key];
  }
}

/// 泛型中的特定类型约束
/// 将泛型约束为某个类型的子类
class Member<T extends Person>{
  T _person;

  /// 构造函数中设置 T _person 成员的值
  Member(this._person);

  /// 获取 _person 的名字
  String getName(){
    return _person.name;
  }
}

涉及到的 Person 和 Student 类 :

代码语言:javascript复制
/// 定义 Dart 类
/// 与 Java 语言类似, 所有的类默认继承 Object 类
class Person{

  /// 定义变量
  String name;
  int age;

  /// 私有字段
  int _achievement;

  /// 标准构造方法, 下面的方法是常用的构造方法写法
  Person(this.name, this.age);

  /// get 方法 : 设置私有字段 achievement 的 get 方法,
  ///            让外界可以访问 Person 对象的 _achievement 私有成员
  int get achievement => _achievement;

  /// set 方法 : 设置私有字段 achievement 的 set 方法,
  ///            让外界可以设置 Person 对象的 _achievement 私有成员值
  set achievement(int achievement){
    _achievement = achievement;
  }

  /// 静态方法 , 通过类名调用
  static log(){
    print("log");
  }

  /// 重写父类的方法
  @override
  String toString() {
    return "$name : $age";
  }
}

/// 继承
class Student extends Person{

  /// 私有变量, 以下划线开始的变量是私有变量
  int _grade;

  String school;
  String city;
  String address;

  /// 父类构造函数调用 : 如果父类有非空参数的构造函数, 子类必须实现相同参数的构造函数
  /// 如果该类有父类 , 那么先调用父类的构造方法 , 完成父类的初始化
  /// 然后才能完成自己的初始化
  ///
  /// this.school 指定自有参数
  /// {this.school} 是可选参数, 可选参数必须在构造函数参数列表中最后一个
  ///
  /// 默认参数 : 可选参数中如果用户不初始化该可选参数 , 那么为其指定一个默认值
  /// {this.city = "北京"} 指定了如果用户不初始化 city 变量, 那么为其初始化 "北京" 字符串值
  ///
  /// 初始化列表 : 冒号后面的内容就是初始化列表
  ///            父类构造器也是初始化列表
  ///            除了父类构造方法之外 , 还可以在子类构造方法体之前初始化示例变量
  ///            不同的初始化实例变量之间使用逗号隔开
  ///
  /// 父类构造方法 : 如果父类没有默认构造方法 (无参构造方法) ,
  ///              必须在初始化列表中调用父类构造函数 , super(name, age) ;
  ///
  /// 构造方法方法体 : 可以省略 ;
  Student(this._grade, String name, int age,
         {this.school, this.city = "北京"})
         : address = "北京市海淀区" ,
         super(name, age);


  // 命名构造方法
  // 定义格式 : 类名.方法名()
  // 父类构造函数 : 如果父类没有默认构造函数, 子类必须调用父类的构造函数
  Student.cover(Student student):super(student.name, student.age);

  // 命名构造方法也可以有方法体
  Student.init(Student student):super(student.name, student.age){
    print("命名构造方法 : name : ${student.name}, age : ${student.age}");
  }

  // 命名工厂构造方法 : factory 类名.方法名
  // 命名工厂构造方法可以有返回值
  // 如果类中有 final 修饰的成员 , 在命名构造方法中必须对其进行初始化
  //    但是在命名工厂构造方法中 , 可以不初始化 final 类型成员
  // 命名工厂构造方法可以有返回值
  factory Student.init2(){
    return Student(1, "Tom", 18);
  }

}

测试代码入口 : 在 main.dart 中的 _MyHomePageState 类中的 build 方法中 ;

代码语言:javascript复制
/// 省略其它源码
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    // 测试泛型
    Generic generic = Generic();
    generic.test();
  }
}

打印结果 :

代码语言:javascript复制
I/flutter (24673): 泛型测试, 类型字符串, 获取的缓存内容为 Tom
I/flutter (24673): 泛型测试, 类型整型, 获取的缓存内容为 18
I/flutter (24673): 泛型类测试, 获取的 T extends Person 泛型的 name 字段为 Tom

五、 相关资源


参考资料 :

  • Flutter 官网 : https://flutter.dev/
  • Flutter 开发文档 : https://flutter.cn/docs ( 强烈推荐 )
  • 官方 GitHub 地址 : https://github.com/flutter
  • Flutter 中文社区 : https://flutter.cn/
  • Flutter 实用教程 : https://flutter.cn/docs/cookbook
  • Flutter CodeLab : https://codelabs.flutter-io.cn/
  • Dart 中文文档 : https://dart.cn/
  • Dart 开发者官网 : https://api.dart.dev/
  • Flutter 中文网 ( 非官方 , 翻译的很好 ) : https://flutterchina.club/ , http://flutter.axuer.com/docs/
  • Flutter 相关问题 : https://flutterchina.club/faq/ ( 入门阶段推荐看一遍 )

博客源码下载 :

  • GitHub 地址 : https://github.com/han1202012/flutter_app_hello ( 随博客进度一直更新 , 有可能没有本博客的源码 )
  • 博客源码快照 : https://download.csdn.net/download/han1202012/15463304( 本篇博客的源码快照 , 可以找到本博客的源码 )

0 人点赞