其实很多时候,我们会面临一个需求,就是从json中取出一个值,并转成指定类型
public static void main(String[] args) {JSONObject jsonObject = JSON.parseObject("{'test': 1}");Long test = (Long) jsonObject.get("test");System.out.println(test);}
但这种强制类型转换可能会出问题,比如上面这几行代码,我们运行一下,可以得到如下结果
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
没错,强制转换异常,这就是我们不愿意看到的结果,那么有什么方式可以避免呢?
我们可以看看FastJson的源代码
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.alibaba.fastjson;import com.alibaba.fastjson.annotation.JSONField;import com.alibaba.fastjson.parser.ParserConfig;import com.alibaba.fastjson.util.TypeUtils;import java.io.Serializable;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Type;import java.math.BigDecimal;import java.math.BigInteger;import java.sql.Timestamp;import java.util.Collection;import java.util.Date;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.Map;import java.util.Set;import java.util.Map.Entry;public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler {private static final long serialVersionUID = 1L;private static final int DEFAULT_INITIAL_CAPACITY = 16;private final Map<String, Object> map;public JSONObject() {this(16, false);}public JSONObject(Map<String, Object> map) {this.map = map;}public JSONObject(boolean ordered) {this(16, ordered);}public JSONObject(int initialCapacity) {this(initialCapacity, false);}public JSONObject(int initialCapacity, boolean ordered) {if (ordered) {this.map = new LinkedHashMap(initialCapacity);} else {this.map = new HashMap(initialCapacity);}}public int size() {return this.map.size();}public boolean isEmpty() {return this.map.isEmpty();}public boolean containsKey(Object key) {return this.map.containsKey(key);}public boolean containsValue(Object value) {return this.map.containsValue(value);}public Object get(Object key) {Object val = this.map.get(key);if (val == null && key instanceof Number) {val = this.map.get(key.toString());}return val;}public JSONObject getJSONObject(String key) {Object value = this.map.get(key);if (value instanceof JSONObject) {return (JSONObject)value;} else {return value instanceof String ? JSON.parseObject((String)value) : (JSONObject)toJSON(value);}}public JSONArray getJSONArray(String key) {Object value = this.map.get(key);if (value instanceof JSONArray) {return (JSONArray)value;} else {return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value);}}public <T> T getObject(String key, Class<T> clazz) {Object obj = this.map.get(key);return TypeUtils.castToJavaBean(obj, clazz);}public <T> T getObject(String key, Type type) {Object obj = this.map.get(key);return TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());}public <T> T getObject(String key, TypeReference typeReference) {Object obj = this.map.get(key);return typeReference == null ? obj : TypeUtils.cast(obj, typeReference.getType(), ParserConfig.getGlobalInstance());}public Boolean getBoolean(String key) {Object value = this.get(key);return value == null ? null : TypeUtils.castToBoolean(value);}public byte[] getBytes(String key) {Object value = this.get(key);return value == null ? null : TypeUtils.castToBytes(value);}public boolean getBooleanValue(String key) {Object value = this.get(key);Boolean booleanVal = TypeUtils.castToBoolean(value);return booleanVal == null ? false : booleanVal;}public Byte getByte(String key) {Object value = this.get(key);return TypeUtils.castToByte(value);}public byte getByteValue(String key) {Object value = this.get(key);Byte byteVal = TypeUtils.castToByte(value);return byteVal == null ? 0 : byteVal;}public Short getShort(String key) {Object value = this.get(key);return TypeUtils.castToShort(value);}public short getShortValue(String key) {Object value = this.get(key);Short shortVal = TypeUtils.castToShort(value);return shortVal == null ? 0 : shortVal;}public Integer getInteger(String key) {Object value = this.get(key);return TypeUtils.castToInt(value);}public int getIntValue(String key) {Object value = this.get(key);Integer intVal = TypeUtils.castToInt(value);return intVal == null ? 0 : intVal;}public Long getLong(String key) {Object value = this.get(key);return TypeUtils.castToLong(value);}public long getLongValue(String key) {Object value = this.get(key);Long longVal = TypeUtils.castToLong(value);return longVal == null ? 0L : longVal;}public Float getFloat(String key) {Object value = this.get(key);return TypeUtils.castToFloat(value);}public float getFloatValue(String key) {Object value = this.get(key);Float floatValue = TypeUtils.castToFloat(value);return floatValue == null ? 0.0F : floatValue;}public Double getDouble(String key) {Object value = this.get(key);return TypeUtils.castToDouble(value);}public double getDoubleValue(String key) {Object value = this.get(key);Double doubleValue = TypeUtils.castToDouble(value);return doubleValue == null ? 0.0D : doubleValue;}public BigDecimal getBigDecimal(String key) {Object value = this.get(key);return TypeUtils.castToBigDecimal(value);}public BigInteger getBigInteger(String key) {Object value = this.get(key);return TypeUtils.castToBigInteger(value);}public String getString(String key) {Object value = this.get(key);return value == null ? null : value.toString();}public Date getDate(String key) {Object value = this.get(key);return TypeUtils.castToDate(value);}public java.sql.Date getSqlDate(String key) {Object value = this.get(key);return TypeUtils.castToSqlDate(value);}public Timestamp getTimestamp(String key) {Object value = this.get(key);return TypeUtils.castToTimestamp(value);}public Object put(String key, Object value) {return this.map.put(key, value);}public JSONObject fluentPut(String key, Object value) {this.map.put(key, value);return this;}public void putAll(Map<? extends String, ? extends Object> m) {this.map.putAll(m);}public JSONObject fluentPutAll(Map<? extends String, ? extends Object> m) {this.map.putAll(m);return this;}public void clear() {this.map.clear();}public JSONObject fluentClear() {this.map.clear();return this;}public Object remove(Object key) {return this.map.remove(key);}public JSONObject fluentRemove(Object key) {this.map.remove(key);return this;}public Set<String> keySet() {return this.map.keySet();}public Collection<Object> values() {return this.map.values();}public Set<Entry<String, Object>> entrySet() {return this.map.entrySet();}public Object clone() {return new JSONObject((Map)(this.map instanceof LinkedHashMap ? new LinkedHashMap(this.map) : new HashMap(this.map)));}public boolean equals(Object obj) {return this.map.equals(obj);}public int hashCode() {return this.map.hashCode();}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Class<?>[] parameterTypes = method.getParameterTypes();Class returnType;String name;JSONField annotation;if (parameterTypes.length == 1) {if (method.getName().equals("equals")) {return this.equals(args[0]);} else {returnType = method.getReturnType();if (returnType != Void.TYPE) {throw new JSONException("illegal setter");} else {name = null;annotation = (JSONField)method.getAnnotation(JSONField.class);if (annotation != null && annotation.name().length() != 0) {name = annotation.name();}if (name == null) {name = method.getName();if (!name.startsWith("set")) {throw new JSONException("illegal setter");}name = name.substring(3);if (name.length() == 0) {throw new JSONException("illegal setter");}name = Character.toLowerCase(name.charAt(0)) + name.substring(1);}this.map.put(name, args[0]);return null;}}} else if (parameterTypes.length == 0) {returnType = method.getReturnType();if (returnType == Void.TYPE) {throw new JSONException("illegal getter");} else {name = null;annotation = (JSONField)method.getAnnotation(JSONField.class);if (annotation != null && annotation.name().length() != 0) {name = annotation.name();}if (name == null) {name = method.getName();if (name.startsWith("get")) {name = name.substring(3);if (name.length() == 0) {throw new JSONException("illegal getter");}name = Character.toLowerCase(name.charAt(0)) + name.substring(1);} else {if (!name.startsWith("is")) {if (name.startsWith("hashCode")) {return this.hashCode();}if (name.startsWith("toString")) {return this.toString();}throw new JSONException("illegal getter");}name = name.substring(2);if (name.length() == 0) {throw new JSONException("illegal getter");}name = Character.toLowerCase(name.charAt(0)) + name.substring(1);}}Object value = this.map.get(name);return TypeUtils.cast(value, method.getGenericReturnType(), ParserConfig.getGlobalInstance());}} else {throw new UnsupportedOperationException(method.toGenericString());}}public Map<String, Object> getInnerMap() {return this.map;}}
仔细看我们会发现,里面有getLong, getInteger, getDouble等一系列的方法,看起来,getLong就可以让我们得到想要的结果,我们尝试着把之前的代码改一下,看一下是否会和我们预期的一致
public static void main(String[] args) {JSONObject jsonObject = JSON.parseObject("{'test': 1}");Long test = jsonObject.getLong("test");System.out.println(test);}

从运行结果可以看出来,这就是我们想要的结果。那为什么强制转换就不行呢,我们可以看看FastJson的源码,看看它是否帮我们做了什么?
仔细阅读,我们会发现getLong的方法里面有这么一句话,TypeUtils.castToLong(value),castToLong的源码如下:
public static Long castToLong(Object value) {if (value == null) {return null;} else if (value instanceof Number) {return ((Number)value).longValue();} else {if (value instanceof String) {String strVal = (String)value;if (strVal.length() == 0 || "null".equals(strVal) || "NULL".equals(strVal)) {return null;}if (strVal.indexOf(44) != 0) {strVal = strVal.replaceAll(",", "");}try {return Long.parseLong(strVal);} catch (NumberFormatException var4) {JSONScanner dateParser = new JSONScanner(strVal);Calendar calendar = null;if (dateParser.scanISO8601DateIfMatch(false)) {calendar = dateParser.getCalendar();}dateParser.close();if (calendar != null) {return calendar.getTimeInMillis();}}}if (value instanceof Map) {Map map = (Map)value;if (map.size() == 2 && map.containsKey("andIncrement") && map.containsKey("andDecrement")) {Iterator iter = map.values().iterator();iter.next();Object value2 = iter.next();return castToLong(value2);}}throw new JSONException("can not cast to long, value : " + value);}}
到这里,我们就知道了,FastJson内部帮我们做了类型转换,其他诸如此类的方法也都差不多,以后如果我们要使用的话,优先使用已提供的方法,避免自己做强制类型转换。
