其实很多时候,我们会面临一个需求,就是从json中取出一个值,并转成指定类型

    1. public static void main(String[] args) {
    2. JSONObject jsonObject = JSON.parseObject("{'test': 1}");
    3. Long test = (Long) jsonObject.get("test");
    4. System.out.println(test);
    5. }

    但这种强制类型转换可能会出问题,比如上面这几行代码,我们运行一下,可以得到如下结果

    1. Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

    没错,强制转换异常,这就是我们不愿意看到的结果,那么有什么方式可以避免呢?
    我们可以看看FastJson的源代码

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by Fernflower decompiler)
    4. //
    5. package com.alibaba.fastjson;
    6. import com.alibaba.fastjson.annotation.JSONField;
    7. import com.alibaba.fastjson.parser.ParserConfig;
    8. import com.alibaba.fastjson.util.TypeUtils;
    9. import java.io.Serializable;
    10. import java.lang.reflect.InvocationHandler;
    11. import java.lang.reflect.Method;
    12. import java.lang.reflect.Type;
    13. import java.math.BigDecimal;
    14. import java.math.BigInteger;
    15. import java.sql.Timestamp;
    16. import java.util.Collection;
    17. import java.util.Date;
    18. import java.util.HashMap;
    19. import java.util.LinkedHashMap;
    20. import java.util.Map;
    21. import java.util.Set;
    22. import java.util.Map.Entry;
    23. public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler {
    24. private static final long serialVersionUID = 1L;
    25. private static final int DEFAULT_INITIAL_CAPACITY = 16;
    26. private final Map<String, Object> map;
    27. public JSONObject() {
    28. this(16, false);
    29. }
    30. public JSONObject(Map<String, Object> map) {
    31. this.map = map;
    32. }
    33. public JSONObject(boolean ordered) {
    34. this(16, ordered);
    35. }
    36. public JSONObject(int initialCapacity) {
    37. this(initialCapacity, false);
    38. }
    39. public JSONObject(int initialCapacity, boolean ordered) {
    40. if (ordered) {
    41. this.map = new LinkedHashMap(initialCapacity);
    42. } else {
    43. this.map = new HashMap(initialCapacity);
    44. }
    45. }
    46. public int size() {
    47. return this.map.size();
    48. }
    49. public boolean isEmpty() {
    50. return this.map.isEmpty();
    51. }
    52. public boolean containsKey(Object key) {
    53. return this.map.containsKey(key);
    54. }
    55. public boolean containsValue(Object value) {
    56. return this.map.containsValue(value);
    57. }
    58. public Object get(Object key) {
    59. Object val = this.map.get(key);
    60. if (val == null && key instanceof Number) {
    61. val = this.map.get(key.toString());
    62. }
    63. return val;
    64. }
    65. public JSONObject getJSONObject(String key) {
    66. Object value = this.map.get(key);
    67. if (value instanceof JSONObject) {
    68. return (JSONObject)value;
    69. } else {
    70. return value instanceof String ? JSON.parseObject((String)value) : (JSONObject)toJSON(value);
    71. }
    72. }
    73. public JSONArray getJSONArray(String key) {
    74. Object value = this.map.get(key);
    75. if (value instanceof JSONArray) {
    76. return (JSONArray)value;
    77. } else {
    78. return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value);
    79. }
    80. }
    81. public <T> T getObject(String key, Class<T> clazz) {
    82. Object obj = this.map.get(key);
    83. return TypeUtils.castToJavaBean(obj, clazz);
    84. }
    85. public <T> T getObject(String key, Type type) {
    86. Object obj = this.map.get(key);
    87. return TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());
    88. }
    89. public <T> T getObject(String key, TypeReference typeReference) {
    90. Object obj = this.map.get(key);
    91. return typeReference == null ? obj : TypeUtils.cast(obj, typeReference.getType(), ParserConfig.getGlobalInstance());
    92. }
    93. public Boolean getBoolean(String key) {
    94. Object value = this.get(key);
    95. return value == null ? null : TypeUtils.castToBoolean(value);
    96. }
    97. public byte[] getBytes(String key) {
    98. Object value = this.get(key);
    99. return value == null ? null : TypeUtils.castToBytes(value);
    100. }
    101. public boolean getBooleanValue(String key) {
    102. Object value = this.get(key);
    103. Boolean booleanVal = TypeUtils.castToBoolean(value);
    104. return booleanVal == null ? false : booleanVal;
    105. }
    106. public Byte getByte(String key) {
    107. Object value = this.get(key);
    108. return TypeUtils.castToByte(value);
    109. }
    110. public byte getByteValue(String key) {
    111. Object value = this.get(key);
    112. Byte byteVal = TypeUtils.castToByte(value);
    113. return byteVal == null ? 0 : byteVal;
    114. }
    115. public Short getShort(String key) {
    116. Object value = this.get(key);
    117. return TypeUtils.castToShort(value);
    118. }
    119. public short getShortValue(String key) {
    120. Object value = this.get(key);
    121. Short shortVal = TypeUtils.castToShort(value);
    122. return shortVal == null ? 0 : shortVal;
    123. }
    124. public Integer getInteger(String key) {
    125. Object value = this.get(key);
    126. return TypeUtils.castToInt(value);
    127. }
    128. public int getIntValue(String key) {
    129. Object value = this.get(key);
    130. Integer intVal = TypeUtils.castToInt(value);
    131. return intVal == null ? 0 : intVal;
    132. }
    133. public Long getLong(String key) {
    134. Object value = this.get(key);
    135. return TypeUtils.castToLong(value);
    136. }
    137. public long getLongValue(String key) {
    138. Object value = this.get(key);
    139. Long longVal = TypeUtils.castToLong(value);
    140. return longVal == null ? 0L : longVal;
    141. }
    142. public Float getFloat(String key) {
    143. Object value = this.get(key);
    144. return TypeUtils.castToFloat(value);
    145. }
    146. public float getFloatValue(String key) {
    147. Object value = this.get(key);
    148. Float floatValue = TypeUtils.castToFloat(value);
    149. return floatValue == null ? 0.0F : floatValue;
    150. }
    151. public Double getDouble(String key) {
    152. Object value = this.get(key);
    153. return TypeUtils.castToDouble(value);
    154. }
    155. public double getDoubleValue(String key) {
    156. Object value = this.get(key);
    157. Double doubleValue = TypeUtils.castToDouble(value);
    158. return doubleValue == null ? 0.0D : doubleValue;
    159. }
    160. public BigDecimal getBigDecimal(String key) {
    161. Object value = this.get(key);
    162. return TypeUtils.castToBigDecimal(value);
    163. }
    164. public BigInteger getBigInteger(String key) {
    165. Object value = this.get(key);
    166. return TypeUtils.castToBigInteger(value);
    167. }
    168. public String getString(String key) {
    169. Object value = this.get(key);
    170. return value == null ? null : value.toString();
    171. }
    172. public Date getDate(String key) {
    173. Object value = this.get(key);
    174. return TypeUtils.castToDate(value);
    175. }
    176. public java.sql.Date getSqlDate(String key) {
    177. Object value = this.get(key);
    178. return TypeUtils.castToSqlDate(value);
    179. }
    180. public Timestamp getTimestamp(String key) {
    181. Object value = this.get(key);
    182. return TypeUtils.castToTimestamp(value);
    183. }
    184. public Object put(String key, Object value) {
    185. return this.map.put(key, value);
    186. }
    187. public JSONObject fluentPut(String key, Object value) {
    188. this.map.put(key, value);
    189. return this;
    190. }
    191. public void putAll(Map<? extends String, ? extends Object> m) {
    192. this.map.putAll(m);
    193. }
    194. public JSONObject fluentPutAll(Map<? extends String, ? extends Object> m) {
    195. this.map.putAll(m);
    196. return this;
    197. }
    198. public void clear() {
    199. this.map.clear();
    200. }
    201. public JSONObject fluentClear() {
    202. this.map.clear();
    203. return this;
    204. }
    205. public Object remove(Object key) {
    206. return this.map.remove(key);
    207. }
    208. public JSONObject fluentRemove(Object key) {
    209. this.map.remove(key);
    210. return this;
    211. }
    212. public Set<String> keySet() {
    213. return this.map.keySet();
    214. }
    215. public Collection<Object> values() {
    216. return this.map.values();
    217. }
    218. public Set<Entry<String, Object>> entrySet() {
    219. return this.map.entrySet();
    220. }
    221. public Object clone() {
    222. return new JSONObject((Map)(this.map instanceof LinkedHashMap ? new LinkedHashMap(this.map) : new HashMap(this.map)));
    223. }
    224. public boolean equals(Object obj) {
    225. return this.map.equals(obj);
    226. }
    227. public int hashCode() {
    228. return this.map.hashCode();
    229. }
    230. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    231. Class<?>[] parameterTypes = method.getParameterTypes();
    232. Class returnType;
    233. String name;
    234. JSONField annotation;
    235. if (parameterTypes.length == 1) {
    236. if (method.getName().equals("equals")) {
    237. return this.equals(args[0]);
    238. } else {
    239. returnType = method.getReturnType();
    240. if (returnType != Void.TYPE) {
    241. throw new JSONException("illegal setter");
    242. } else {
    243. name = null;
    244. annotation = (JSONField)method.getAnnotation(JSONField.class);
    245. if (annotation != null && annotation.name().length() != 0) {
    246. name = annotation.name();
    247. }
    248. if (name == null) {
    249. name = method.getName();
    250. if (!name.startsWith("set")) {
    251. throw new JSONException("illegal setter");
    252. }
    253. name = name.substring(3);
    254. if (name.length() == 0) {
    255. throw new JSONException("illegal setter");
    256. }
    257. name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
    258. }
    259. this.map.put(name, args[0]);
    260. return null;
    261. }
    262. }
    263. } else if (parameterTypes.length == 0) {
    264. returnType = method.getReturnType();
    265. if (returnType == Void.TYPE) {
    266. throw new JSONException("illegal getter");
    267. } else {
    268. name = null;
    269. annotation = (JSONField)method.getAnnotation(JSONField.class);
    270. if (annotation != null && annotation.name().length() != 0) {
    271. name = annotation.name();
    272. }
    273. if (name == null) {
    274. name = method.getName();
    275. if (name.startsWith("get")) {
    276. name = name.substring(3);
    277. if (name.length() == 0) {
    278. throw new JSONException("illegal getter");
    279. }
    280. name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
    281. } else {
    282. if (!name.startsWith("is")) {
    283. if (name.startsWith("hashCode")) {
    284. return this.hashCode();
    285. }
    286. if (name.startsWith("toString")) {
    287. return this.toString();
    288. }
    289. throw new JSONException("illegal getter");
    290. }
    291. name = name.substring(2);
    292. if (name.length() == 0) {
    293. throw new JSONException("illegal getter");
    294. }
    295. name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
    296. }
    297. }
    298. Object value = this.map.get(name);
    299. return TypeUtils.cast(value, method.getGenericReturnType(), ParserConfig.getGlobalInstance());
    300. }
    301. } else {
    302. throw new UnsupportedOperationException(method.toGenericString());
    303. }
    304. }
    305. public Map<String, Object> getInnerMap() {
    306. return this.map;
    307. }
    308. }

    仔细看我们会发现,里面有getLong, getInteger, getDouble等一系列的方法,看起来,getLong就可以让我们得到想要的结果,我们尝试着把之前的代码改一下,看一下是否会和我们预期的一致

    1. public static void main(String[] args) {
    2. JSONObject jsonObject = JSON.parseObject("{'test': 1}");
    3. Long test = jsonObject.getLong("test");
    4. System.out.println(test);
    5. }

    image.png

    从运行结果可以看出来,这就是我们想要的结果。那为什么强制转换就不行呢,我们可以看看FastJson的源码,看看它是否帮我们做了什么?

    仔细阅读,我们会发现getLong的方法里面有这么一句话,TypeUtils.castToLong(value),castToLong的源码如下:

    1. public static Long castToLong(Object value) {
    2. if (value == null) {
    3. return null;
    4. } else if (value instanceof Number) {
    5. return ((Number)value).longValue();
    6. } else {
    7. if (value instanceof String) {
    8. String strVal = (String)value;
    9. if (strVal.length() == 0 || "null".equals(strVal) || "NULL".equals(strVal)) {
    10. return null;
    11. }
    12. if (strVal.indexOf(44) != 0) {
    13. strVal = strVal.replaceAll(",", "");
    14. }
    15. try {
    16. return Long.parseLong(strVal);
    17. } catch (NumberFormatException var4) {
    18. JSONScanner dateParser = new JSONScanner(strVal);
    19. Calendar calendar = null;
    20. if (dateParser.scanISO8601DateIfMatch(false)) {
    21. calendar = dateParser.getCalendar();
    22. }
    23. dateParser.close();
    24. if (calendar != null) {
    25. return calendar.getTimeInMillis();
    26. }
    27. }
    28. }
    29. if (value instanceof Map) {
    30. Map map = (Map)value;
    31. if (map.size() == 2 && map.containsKey("andIncrement") && map.containsKey("andDecrement")) {
    32. Iterator iter = map.values().iterator();
    33. iter.next();
    34. Object value2 = iter.next();
    35. return castToLong(value2);
    36. }
    37. }
    38. throw new JSONException("can not cast to long, value : " + value);
    39. }
    40. }

    到这里,我们就知道了,FastJson内部帮我们做了类型转换,其他诸如此类的方法也都差不多,以后如果我们要使用的话,优先使用已提供的方法,避免自己做强制类型转换。