TJSONObject查找效率如何?大JSON场景下能否优化?
TJSONObject.GetValue/TryGetValue 性能与优化方案
1. 默认实现的效率与遍历行为
Delphi原生的TJSONObject内部通过TList<TJSONPair>存储键值对,调用GetValue或TryGetValue时,默认采用线性遍历逻辑:
- 若目标键存在,遍历到匹配的
TJSONPair后立即停止; - 若目标键不存在,会遍历完所有条目才返回查找失败的结果。
当JSON包含数千条条目时,单次查找的时间复杂度为O(n)。如果频繁执行查找操作(比如循环内多次调用),性能会随条目数量线性下降,耗时会明显增加。
2. 无额外依赖的优化方案
可以通过继承TJSONObject并扩展哈希表缓存的方式优化查找速度,核心思路是在子类内部维护一个TDictionary<string, TJSONValue>,将键与对应的值做映射,把查找复杂度降到O(1)。具体实现要点:
- 继承
TJSONObject,新增私有字段FKeyMap: TDictionary<string, TJSONValue>用于缓存键值映射; - 在构造函数中初始化字典,析构函数中释放资源;
- 重写
GetValue、TryGetValue方法,优先从字典中查找,找不到再走原生逻辑并同步字典; - 覆盖
AddPair、RemovePair、Clear等修改键值对的方法,保证字典与原列表的数据同步(添加时插入字典,删除时移除对应条目); - 如需兼容键的大小写,可以在插入字典时统一转换为小写/大写存储。
简化示例代码
type THashedJSONObject = class(TJSONObject) private FKeyMap: TDictionary<string, TJSONValue>; procedure SyncKeyMap; public constructor Create; override; destructor Destroy; override; function GetValue(const Name: string): TJSONValue; override; function TryGetValue(const Name: string; out Value: TJSONValue): Boolean; override; function AddPair(const Pair: TJSONPair): TJSONObject; override; function RemovePair(const Name: string): TJSONPair; override; procedure Clear; override; end; constructor THashedJSONObject.Create; begin inherited; FKeyMap := TDictionary<string, TJSONValue>.Create; SyncKeyMap; end; destructor THashedJSONObject.Destroy; begin FKeyMap.Free; inherited; end; procedure THashedJSONObject.SyncKeyMap; var Pair: TJSONPair; begin FKeyMap.Clear; for Pair in Pairs do FKeyMap.AddOrSetValue(Pair.JsonString.Value, Pair.JsonValue); end; function THashedJSONObject.GetValue(const Name: string): TJSONValue; begin if FKeyMap.TryGetValue(Name, Result) then Exit; Result := inherited GetValue(Name); if Assigned(Result) then FKeyMap.AddOrSetValue(Name, Result); end; function THashedJSONObject.TryGetValue(const Name: string; out Value: TJSONValue): Boolean; begin Result := FKeyMap.TryGetValue(Name, Value); if not Result then begin Result := inherited TryGetValue(Name, Value); if Result then FKeyMap.AddOrSetValue(Name, Value); end; end; function THashedJSONObject.AddPair(const Pair: TJSONPair): TJSONObject; begin Result := inherited AddPair(Pair); if Assigned(Pair) then FKeyMap.AddOrSetValue(Pair.JsonString.Value, Pair.JsonValue); end; function THashedJSONObject.RemovePair(const Name: string): TJSONPair; begin Result := inherited RemovePair(Name); if Assigned(Result) then FKeyMap.Remove(Name); end; procedure THashedJSONObject.Clear; begin inherited; FKeyMap.Clear; end;
注意事项
- 若JSON对象会被频繁修改,必须确保所有修改操作都同步更新哈希表,否则会出现数据不一致的问题;
- 原生
TJSONObject的Pairs列表是有序的,哈希表不保证顺序,若需保留顺序可以结合TOrderedDictionary(Delphi XE7及以上版本支持)。
内容的提问来源于stack exchange,提问作者Peter Jones
相关产品推荐
相关产品推荐

