在json的使用过程中忽然发现一个有意思的点,传入JSONObject构造函数的String 中有Unicode,但取出来之后却变成了对应的中文,于是就有了下面的探索之旅。
json_1.pngconfig是{"title":"\u70b9\u5e7f\u544a\u514d\u8d39\u542c\u4f1a\u5458\u6b4c","time":10}。
从截图中可以看出在构造出的JsonObject中就已经完成转换,
所以unicode 转成中文不是在getString 中处理,而是在config 参数传入Json的构造函数中转换号的。换句话说就是在构造JsonObject的时候就完成了。
接下来就从构造函数开始看看,Json的构造函数比较简单:
public JSONObject(@NonNull String json) throws JSONException {
this(new JSONTokener(json));
}
Json的构造函数中会新建一个JSONTokener,这个时候新建的对象并没有将unicode 转成中文。
json_2.png
继续看JSONObject的构造函数,JSONTokener调用nextValue() 生成一个Object,这个时候生成的object 对象已经完成了unicode 转成中文的转换过程。
json_3.png
接下来不太好调试,只能硬看代码了,先从开始JSONTokener类的nextValue()方法开始
public Object nextValue() throws JSONException {
int c = nextCleanInternal();
switch (c) {
case -1:
throw syntaxError("End of input");
case '{':
return readObject();
case '[':
return readArray();
case '\'':
case '"':
return nextString((char) c);
default:
pos--;
return readLiteral();
}
}
调用了nextCleanInternal()这个方法,它会从头到尾的逐个字符的解析,对于一些字符做一些处理。例如空格,换行,转义符等!
这里先跳过,大概就是返回一个索引。这里我们是第一次调用nextValue() 方法,所以肯定是以 { 开头,所以直接看readObject()。
private JSONObject readObject() throws JSONException {
JSONObject result = new JSONObject(); // 新建一个JSONObject对象
/* Peek to see if this is the empty object. */
int first = nextCleanInternal();
if (first == '}') {
return result;
} else if (first != -1) {
pos--;
}
while (true) {
Object name = nextValue();
if (!(name instanceof String)) { //对json的key 进行检查, 只能是非空的String 类型。
if (name == null) {
throw syntaxError("Names cannot be null");
} else {
throw syntaxError("Names must be strings, but " + name
+ " is of type " + name.getClass().getName());
}
}
/*
* Expect the name/value separator to be either a colon ':', an
* equals sign '=', or an arrow "=>". The last two are bogus but we
* include them because that's what the original implementation did.
*/
int separator = nextCleanInternal(); // 此处又碰到了我们跳过的方法,😂 继续跳过,先简单理解返回一个位置索引。
if (separator != ':' && separator != '=') { // key 之后的分隔符必须是 : 或者 = ,分隔符是 :,比较常见,但什么情况下分隔符是 = ,此处有疑问!
throw syntaxError("Expected ':' after " + name);
}
if (pos < in.length() && in.charAt(pos) == '>') {
pos++;
}
result.put((String) name, nextValue()); // 此处再次调用了nextValue(),将key 和nextValue()的返回值存储在result 这个JsonObject 对象中
switch (nextCleanInternal()) {
case '}':
return result;
case ';':
case ',':
continue;
default:
throw syntaxError("Unterminated object");
}
}
}
关键代码是 result.put((String) name, nextValue()); // 此处再次调用了nextValue(),将key 和nextValue()的返回值存储在result 这个JsonObject 对象中。不过此时是第二次调用nextValue(),而且读取的位置也从string 的开头,来到了key 后面分分隔符了。此时原始字符串的分隔符是 “ ,所以实际执行的代码是如下代码中的nextString()。
public Object nextValue() throws JSONException {
int c = nextCleanInternal();
switch (c) {
case '{':
return readObject();
case '\'':
case '"':
return nextString((char) c);
default:
pos--;
return readLiteral();
}
}
nextString() 的代码如下:
public String nextString(char quote) throws JSONException {
/*
* For strings that are free of escape sequences, we can just extract
* the result as a substring of the input. But if we encounter an escape
* sequence, we need to use a StringBuilder to compose the result.
*/
StringBuilder builder = null;
/* the index of the first character not yet appended to the builder. */
int start = pos;
while (pos < in.length()) {
int c = in.charAt(pos++);
if (c == quote) {
if (builder == null) {
// a new string avoids leaking memory
return new String(in.substring(start, pos - 1));
} else {
builder.append(in, start, pos - 1);
return builder.toString();
}
}
if (c == '\\') {
if (pos == in.length()) {
throw syntaxError("Unterminated escape sequence");
}
if (builder == null) {
builder = new StringBuilder();
}
builder.append(in, start, pos - 1);
builder.append(readEscapeCharacter());
start = pos;
}
}
throw syntaxError("Unterminated string");
}
比较关键的方法是readEscapeCharacter,继续跟进去看看,关键代码如下:
private char readEscapeCharacter() throws JSONException {
char escaped = in.charAt(pos++);
switch (escaped) {
case 'u':
if (pos + 4 > in.length()) {
throw syntaxError("Unterminated escape sequence");
}
String hex = in.substring(pos, pos + 4);
pos += 4;
try {
return (char) Integer.parseInt(hex, 16);
} catch (NumberFormatException nfe) {
throw syntaxError("Invalid escape sequence: " + hex);
}
}
}
此时大概就看出,此处就将unicode转成中文,取出四位char, 然后转成Integter. 最后再转成Integer对应的char.
还有很多疑问,需要补下Json 的解析以及对应的细节
网友评论