
本文介绍如何通过面向对象的继承结构,优雅地封装json所有合法值类型(null、布尔、数字、字符串、数组、对象),避免泛型擦除与强制类型转换,提升api易用性与类型安全性。
本文介绍如何通过面向对象的继承结构,优雅地封装json所有合法值类型(null、布尔、数字、字符串、数组、对象),避免泛型擦除与强制类型转换,提升api易用性与类型安全性。
在实现符合 RFC 8259 标准的 JSON 解析器时,核心挑战在于:如何统一建模 value 的七种互斥形态(null / true / false / number / string / array / object),同时为用户提供类型安全、语义清晰的访问接口(如 asObject()、asNumber())。你当前采用的 Value 类包裹 Object 字段虽能工作,但存在明显缺陷:类型信息丢失、运行时需冗余 instanceof 判断、无法静态校验方法调用合法性,且 toString() 中的手动分支逻辑难以维护。
更优解是构建轻量级、不可变的继承体系——以抽象基类 JsonValue 为根,为每种 JSON 原生类型定义具体子类:
// 抽象基类:提供统一入口与类型断言
abstract class JsonValue {
public abstract boolean isNull();
public abstract boolean isBoolean();
public abstract boolean isNumber();
public abstract boolean isString();
public abstract boolean isArray();
public abstract boolean isObject();
// 安全转换方法(失败时抛出 IllegalStateException)
public JsonNull asNull() {
if (!isNull()) throw new IllegalStateException("Expected null, got " + this.getClass().getSimpleName());
return (JsonNull) this;
}
public JsonBoolean asBoolean() {
if (!isBoolean()) throw new IllegalStateException("Expected boolean, got " + this.getClass().getSimpleName());
return (JsonBoolean) this;
}
public JsonNumber asNumber() {
if (!isNumber()) throw new IllegalStateException("Expected number, got " + this.getClass().getSimpleName());
return (JsonNumber) this;
}
public JsonString asString() {
if (!isString()) throw new IllegalStateException("Expected string, got " + this.getClass().getSimpleName());
return (JsonString) this;
}
public JsonArray asArray() {
if (!isArray()) throw new IllegalStateException("Expected array, got " + this.getClass().getSimpleName());
return (JsonArray) this;
}
public JsonObject asObject() {
if (!isObject()) throw new IllegalStateException("Expected object, got " + this.getClass().getSimpleName());
return (JsonObject) this;
}
}
// 具体实现示例(省略部分细节)
final class JsonNull extends JsonValue {
@Override public boolean isNull() { return true; }
@Override public String toString() { return "null"; }
}
final class JsonBoolean extends JsonValue {
private final boolean value;
JsonBoolean(boolean value) { this.value = value; }
@Override public boolean isBoolean() { return true; }
@Override public String toString() { return String.valueOf(value); }
}
final class JsonNumber extends JsonValue {
private final BigDecimal value;
JsonNumber(BigDecimal value) { this.value = value; }
@Override public boolean isNumber() { return true; }
@Override public String toString() { return value.toPlainString(); }
}
此设计带来三大优势:
✅ 类型安全:parser.get("key").asObject() 在编译期无法被误调用于非对象值,运行时异常明确指向语义错误;
✅ 零反射开销:instanceof 检查由 JVM 高效优化,远优于 getClass().getName() 字符串匹配;
✅ 可扩展性强:新增类型(如 JsonBinary)只需继承 JsonValue 并实现对应方法,无需修改现有逻辑。
注意事项:
- 所有子类应设计为 final 且不可变(字段 private final),确保线程安全与行为稳定;
- JsonArray 和 JsonObject 需分别持有 List
和 Map ,递归构成完整树形结构; - null 值必须用 JsonNull 实例表示(而非 null 引用),避免空指针风险;
- 若需支持流式解析(如 JsonParser),可将 JsonValue 作为解析器的输出契约,保持接口一致性。
最终,用户代码将变得直观而健壮:
JsonValue root = parser.parse(jsonString);
JsonObject obj = root.asObject(); // 编译期+运行时双重保障
String name = obj.get("name").asString().value(); // 链式调用,无强制转换
int count = obj.get("items").asArray().size(); // 类型语义一目了然
这种设计不仅契合 RFC 的语法定义,更将 JSON 的“值即类型”本质映射为 Java 的类型系统,是工业级 JSON 库(如 Jackson、Gson 内部模型)的通用范式。











