造輪子是理解技術本質的最佳途徑。本文實現一個**極簡 JSON 庫 (MyJSON)**,支持 **Bean/Map/List/Array/基本類型** 雙向轉換,核心邏輯僅靠**遞歸 + 反射 + 字符串流式處理**,代碼量 < 300 行,適合學習 JSON 序列化核心原理。
public static String toJSON(Object object) {
StringBuffer json = new StringBuffer();
if (object instanceof Map) {
writeMap(json, object);
} else if (object instanceof List || object.getClass().isArray()) {
writeList(json, object);
} else {
writeBean(json, object); // 含基本類型包裝類
}
return json.toString();
}
// 1. Bean → { "field": value, ... }
private static void writeBean(StringBuffer json, Object obj) {
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
int i = 0;
for (Field field : fields) {
try {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
Method getter = pd.getReadMethod();
Object value = getter.invoke(obj);
if (i++ == 0) json.append('{'); else json.append(',');
json.append('"').append(field.getName()).append("\":");
writeValue(json, value); // 遞歸寫入值
} catch (Exception ignored) {}
}
if (i == 0) json.append('"').append(obj.toString()).append('"'); // 非 Bean 直接 toString
else json.append('}');
}
// 2. Map → { "key": value, ... }
private static void writeMap(StringBuffer json, Object obj) {
Map<?,?> map = (Map<?,?>) obj;
json.append('{');
int i = 0;
for (Map.Entry<?,?> entry : map.entrySet()) {
if (entry.getKey() != null) {
if (i++ != 0) json.append(',');
json.append('"').append(entry.getKey().toString()).append("\":");
writeValue(json, entry.getValue());
}
}
json.append('}');
}
// 3. List/Array → [ value, ... ]
private static void writeList(StringBuffer json, Object obj) {
List<?> list = obj.getClass().isArray() ? Arrays.asList((Object[]) obj) : (List<?>) obj;
json.append('[');
for (int i = 0; i < list.size(); i++) {
if (i != 0) json.append(',');
writeValue(json, list.get(i));
}
json.append(']');
}
// 4. 值類型分發
private static void writeValue(StringBuffer json, Object value) {
if (value == null) { json.append("null"); return; }
if (value instanceof String) json.append('"').append(escape(value.toString())).append('"');
else if (value instanceof Integer) json.append(value);
else if (value instanceof Boolean) json.append(value);
else if (value instanceof Character) json.append('"').append(value).append('"');
else if (value instanceof Long) json.append(value);
else if (value instanceof Double) json.append(value);
else if (value instanceof Float) json.append(value);
else if (value instanceof Map) writeMap(json, value);
else if (value instanceof List || value.getClass().isArray()) writeList(json, value);
else writeBean(json, value); // 其它對象視為 Bean
}
// 5. 字符串轉義
private static String escape(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
}
public static Object fromJSON(String json) {
json = json.trim();
if (json.startsWith("{")) return parseMap(json, new int[]{1});
if (json.startsWith("[")) return parseList(json, new int[]{1});
throw new IllegalArgumentException("JSON must start with { or [");
}
// 1. 解析 Map { "key": value, ... }
private static Map<String,Object> parseMap(String json, int[] pos) {
Map<String,Object> map = new HashMap<>();
while (pos[0] < json.length()) {
skipBlanks(json, pos);
if (json.charAt(pos[0]) == '}') { pos[0]++; break; } // 空 Map 或結束
String key = parseString(json, pos); // 解析 "key"
skipBlanks(json, pos);
expectChar(json, pos, ':'); // 跳過 :
Object value = parseValue(json, pos); // 遞歸解析值
map.put(key, value);
skipBlanks(json, pos);
char c = json.charAt(pos[0]);
if (c == '}') { pos[0]++; break; }
if (c == ',') { pos[0]++; continue; }
throw new IllegalArgumentException("Expect } or , at " + pos[0]);
}
return map;
}
// 2. 解析 List [ value, ... ]
private static List<Object> parseList(String json, int[] pos) {
List<Object> list = new ArrayList<>();
while (pos[0] < json.length()) {
skipBlanks(json, pos);
if (json.charAt(pos[0]) == ']') { pos[0]++; break; }
Object value = parseValue(json, pos);
list.add(value);
skipBlanks(json, pos);
char c = json.charAt(pos[0]);
if (c == ']') { pos[0]++; break; }
if (c == ',') { pos[0]++; continue; }
throw new IllegalArgumentException("Expect ] or , at " + pos[0]);
}
return list;
}
// 3. 解析值:字符串/數字/布爾/null/Map/List
private static Object parseValue(String json, int[] pos) {
skipBlanks(json, pos);
char c = json.charAt(pos[0]);
if (c == '"') return parseString(json, pos);
if (c == '{') { pos[0]++; return parseMap(json, pos); }
if (c == '[') { pos[0]++; return parseList(json, pos); }
if (c == 't') { pos[0] += 4; return true; } // true
if (c == 'f') { pos[0] += 5; return false; } // false
if (c == 'n') { pos[0] += 4; return null; } // null
// 數字解析
int start = pos[0];
while (pos[0] < json.length() && isNumberChar(json.charAt(pos[0]))) pos[0]++;
String numStr = json.substring(start, pos[0]).trim();
return parseNumber(numStr);
}
// 4. 解析字符串 (處理轉義)
private static String parseString(String json, int[] pos) {
// pos[0] 指向開頭 "
pos[0]++; // 跳過 "
StringBuilder sb = new StringBuilder();
while (pos[0] < json.length()) {
char c = json.charAt(pos[0]++);
if (c == '"') break; // 結束
if (c == '\\') { // 轉義
if (pos[0] >= json.length()) throw new IllegalArgumentException("Incomplete escape");
char esc = json.charAt(pos[0]++);
switch (esc) {
case '"': sb.append('"'); break;
case '\\': sb.append('\\'); break;
case 'n': sb.append('\n'); break;
case 'r': sb.append('\r'); break;
case 't': sb.append('\t'); break;
default: sb.append(esc); // 其它按原樣
}
} else {
sb.append(c);
}
}
return sb.toString();
}
// 5. 數字解析
private static Number parseNumber(String s) {
if (s.contains(".") || s.contains("e") || s.contains("E")) {
try { return Double.parseDouble(s); } catch (NumberFormatException e) { return Float.parseFloat(s); }
} else {
try { return Long.parseLong(s); } catch (NumberFormatException e) { return Integer.parseInt(s); }
}
}
// 輔助
private static void skipBlanks(String json, int[] pos) {
while (pos[0] < json.length() && " \t\r\n".indexOf(json.charAt(pos[0])) >= 0) pos[0]++;
}
private static void expectChar(String json, int[] pos, char expected) {
skipBlanks(json, pos);
if (pos[0] >= json.length() || json.charAt(pos[0]) != expected)
throw new IllegalArgumentException("Expect '" + expected + "' at " + pos[0]);
pos[0]++;
}
private static boolean isNumberChar(char c) {
return "0123456789.-+eE".indexOf(c) >= 0;
}
// 序列化
TestBean bean = new TestBean();
bean.setName("Stri\"ngTe[]}xt");
bean.setFlag(true);
bean.setCount(233);
bean.setRatio(3.14f);
Map<String,Object> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", 100);
bean.setMap(map);
bean.setList(Arrays.asList("a", "b", map));
System.out.println(MyJSON.toJSON(bean));
// 輸出: {"name":"Stri\"ngTe[]}xt","flag":true,"count":233,"ratio":3.14,"map":{"k1":"v1","k2":100},"list":["a","b",{"k1":"v1","k2":100}]}
// 反序列化
String json = "{\"users\":[{\"name\":\"A\",\"age\":20},{\"name\":\"B\",\"age\":25}]}";
Map<String,Object> parsed = (Map<String,Object>) MyJSON.fromJSON(json);
List<Object> users = (List<Object>) parsed.get("users");
users.forEach(u -> System.out.println(((Map<String,Object>)u).get("name")));
| 維度 | MyJSON (教學級) | 生產級庫 |
|---|---|---|
| 性能 | 反射+字符串拼接,慢 10-100 倍 | 字節碼生成/直接內存操作、對象池、SIMD 加速 |
| 功能 | 基礎類型、Bean/Map/List | 流式 API、樹模型、日期/時間、多態、自定義序列化、Schema 驗證、YAML/CBOR 支持 |
| 健壯性 | 簡單報錯、不處理循環引用、大數字精度丟失 | 循環引用檢測、大數字 (BigDecimal)、嚴格/寬容模式、安全反序列化 |
| 易用性 | 手動調用 | 註解驅動、模塊化、Spring 集成、GraalVM 原生 |
手寫 JSON 庫讓我們直觀理解:
生產環境**堅決使用成熟庫**,但理解其內核原理,能讓你在排查序列化異常、優化 JSON 性能、設計自定義協議時游刃有餘。