Dart⾼级(⼀)——泛型与JsonToBean
从 Flutter 发布到现在, 越来越多⼈开始尝试使⽤ Dart 来完成部分功能;
Dart 的前⽣今世⼀类的话题,这⾥就不展开了,只要知道 Flutter 是 google 推出跨平台⽅案就好,⾄少不必担⼼Dart性能与⽣态问题(如果google真的想⽀持的话).
先看⼀下最终的效果显⽰:
Dart 语⾔
根据最新的语⾔排⾏榜…不好意思,没到Dart,就⽬前来看,在前端没拼过JS,在其他领域好像也就⽬前 Flutter 在⽀持,不过相信随着Flutter 盛⾏,情况会越来越好的.
Dart 语⾔有两种模式:JIT,AOT;这个和之前 Android/Java 情况很相似,JVM ⼀直采⽤解释执⾏的⽅式, 直到 ART 出现,Android端才开始AOT 模式;
JIT⽐较⽅便,不需要提前编译,AOT 运⾏时⽐较快,⽽ Flutter 则在 debug 和 release 时,分别适⽤不同模式,保证开发效率以及应⽤流畅.
说了那么多,还没有到正题,接下来,我们来看下 Dart 中⽐较 “特殊” 的特性:泛型
Dart泛型与其他泛型
⾸先来看⼀段关于泛型的 Dart 代码(排列组合:C^2_5):
List<int> a =<int>[];
List<num> b =<num>[];
List<dynamic> c =<dynamic>[];
List<Object> d =<Object>[];
List e =[];
print(a.runtimeType == b.runtimeType);  // false
print(a.runtimeType == c.runtimeType);  // false
print(a.runtimeType == d.runtimeType);  // false
print(a.runtimeType == e.runtimeType);  // false
print(b.runtimeType == c.runtimeType);  // false
print(b.runtimeType == d.runtimeType);  // false
print(b.runtimeType == e.runtimeType);  // false
print(c.runtimeType == d.runtimeType);  // false
print(c.runtimeType == e.runtimeType);  // true
print(d.runtimeType == e.runtimeType);  // false
虽然都是 List 类型,但泛型不同,获取到的runtimeType都不同,由此可知:
Dart中泛型运⾏时依旧存在.
相⽐之下,Java中的泛型就⽐较随意了:
List<Integer> a = new ArrayList<>();
List<Object> b = new ArrayList<>();
List c = new ArrayList<>();
java泛型在运⾏时,会被擦除,所以上⾯的a,b,c判断时都属于List类型.
再回到前⾯ Dart 部分,可以看到只有变量c和e的运⾏时类型相同,并且如果使⽤编译器的话,就可以发现:
List c =<dynamic>[];
List 其实就是 List,两者是⼀样的.
在知道了dart的泛型特性后,不禁会思考:List和List,或者说和List是什么关系?和List呢?
还是开始的dart⽰例,在后⾯我们添加⼏⾏判断(变量b的类型为List<num>)
print(b is List<int>);  //  false
print(b is List<num>);  //  true
print(b is List<Comparable>);  //  true
print(b is List);  //  true
Comparable是num类实现的抽象类,根据验证结果可知:
dart泛型List时,泛型为⽗类的List是泛型为⼦类List的⽗类
这个有点绕,理解这个意思就⾏;其实看到这⾥,如果之前有过java开发经验的话,就会发现这个其实和java中的数组很相似,
这个图说明了java中数组之间是存在继承关系的,并且和实际类之间的继承关系相似.
接下来我们看⼀下泛型类中泛型的关系;
void main(){
var aa = AA.name("123");
}
class AA<T>{
T field;
AA.name(this.field);
void test(){
print("".runtimeType); //String
print(T); //String
print(field.runtimeType == T);  //true
}
}
相信⼤家对这段代码以及结果都没有什么疑问,泛型在传递之后,到了类AA中仍然为String类型,但下⾯这段代码就不同了:
void main(){
var aa = AA.name([]);
json值的类型有哪些
}
class AA<T>{
T field;
AA.name(this.field);
void test(){
print([].runtimeType); //List<dynamic>
print(T); //List<dynamic>
print(field.runtimeType == T);  //false
}
}
我们在创建类时,指定泛型为List(或者说是List),然后在AA中判断,发现泛型T和field的运⾏时类型不同,虽然toString是⼀样的,但如果打印hashCode可以发现,对应着两个不同的Type.
加⼊我们传⼊⼀个map类型,结果更是不如⼈意
void main(){
var aa = AA.name({"ss":1});
}
class AA<T>{
T field;
AA.name(this.field);
void test(){
print(field.runtimeType); // _InternalLinkedHashMap<String, int>
print(T); // Map<String, int>
print(field.runtimeType == T); // false
}
}
实际类型是泛型的⼀个实现类;
那假如传⼊⼀个⾃定义泛型类呢?
void main(){
var aa = AA.name(BB<num>());
}
class AA<T>{
T field;
AA.name(this.field);
void test(){
print(field.runtimeType); // BB<num>
print(T); //  BB<num>
print(field.runtimeType == T); // true
}
}
class BB<T>{}
还好,⾃定义泛型类时,运⾏时runtimeType与泛型Type是相同的
关于dart泛型的探讨只进⾏到这⾥,⼤概总结⼀下:
1. 泛型在运⾏时保留
2. List泛型之间存在关系,可以通过 is 进⾏判断,如 field is List
3. List泛型即便toString⽅法返回相同的值,也可能是两个不同的Type
有了上⾯的论断,接下来进⼊正题
dart-bean
bean只是我们通⽤的⼀种class类的说明,⽤于表明数据模型.
这⾥还是先看⼀下其他语⾔中的bean;
先看java中通常的做法:
public class TestBean {
private String username;
private boolean isVip;
public String getUsername(){
return username;
}
public TestBean setUsername(String username){
this.username = username;
return this;
}
public boolean isVip(){
return isVip;
}
public TestBean setVip(boolean vip){
isVip = vip;
return this;
}
}
kotlin中表⽰形式会简单的多:
data class TestBean(
var username: String? = null,
var isVip: Boolean =false
)
其实bean的代码提现不是关键,重要的地⽅在于,如何⽅便的为bean赋值和操作bean,因为 JVM 语⾔可以进⾏反射,因此,在获取到后台传⼊的json格式数据时,我们可以很⽅便的通过⼀些库完成⾃动赋值操作:
var bean = Gson().fromJson("{\"username\":\"www\",\"isVip\":false}",TestBean::class.java)
在dart中,bean的代码表现形式和其他语⾔基本相同,都是在单独的class中声明成员变量:
class TestBean {
String username;
bool isVip;
}
如果只是单纯的dart项⽬,我们仍然可以通过镜像功能来为bean赋值:
import'dart:mirrors';
class TestBean {
String username;
bool isVip;
}
void main(){
Map<String, dynamic> json ={
"username":"www",
"isVip": false,
};
var class_bean = reflectClass(TestBean);
var obj = pty, []).reflectee;
var instance_bean = reflect(obj);
class_bean.declarations.forEach((key, value){
if(value is VariableMirror){
var key_string = RegExp("^Symbol\\(\"(.+?)\"\\)\$")
.String())
.group(1);
instance_bean.setField(key, json[key_string]);
}
});
print("${obj.username}${obj.isVip}"); // www  false
}
虽然dart的镜像功能看起来很是"不爽",但确实是有这个实现的.
不过有些不幸的是,在Flutter中,dart不允许使⽤镜像功能,具体原因可以实战中提到⼀段话:
很多⼈可能会问Flutter中有没有像Java开发中的Gson/Jackson⼀样的Json序列化类库?答案是没有!因为这样的库需要使⽤运⾏时反射,这在Flutter中是禁⽤的。运⾏时反射会⼲扰Dart的tree shaking,使⽤tree shaking,可以在release版中“去除”未使⽤的代码,这可以显著优化应⽤程序的⼤⼩。由于反射会默认应⽤到所有代码,因此tree shaking会很难⼯作,因为在启⽤反射时很难知道哪些代码未被使⽤,因此冗余代码很难剥离,所以Flutter中禁⽤了Dart的反射功能,⽽正因如此也就⽆法实现动态转化Model的功能。
因此,如果想在Flutter中实现bean,就需要其他的⼀些技巧.
flutter dart-bean
⽬前⼤多数情况下,都是在bean类中添加命名构造函数,然后通过⼯具⾃动⽣成部分代码帮助解析和构建bean.
例如上⾯的bean类会对应⽣成如下代码:
class Response {
String username;
bool isVip;
Response.fromJsonMap(Map<String, dynamic> map)
: username = map["username"],
isVip = map["isVip"];
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = new Map<String, dynamic>();
data['username']= username;
data['isVip']= isVip;
return data;
}
}
即多添加两部分内容:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。