Gson全解析之二:JsonReader的其它方法
Posted 王梵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gson全解析之二:JsonReader的其它方法相关的知识,希望对你有一定的参考价值。
上篇文章的示例代码
String json = "\\"name\\":\\"王成wisely\\",\\"age\\":\\"24\\"";
private void readJson2User()
User user = new User();
StringReader reader = new StringReader(json);
JsonReader jsonReader = new JsonReader(reader);
try
jsonReader.beginObject();
while (jsonReader.hasNext())
String name = jsonReader.nextName();
switch (name)
case "name":
user.name = jsonReader.nextString();
break;
case "age":
user.age = jsonReader.nextInt();
break;
jsonReader.endObject();
catch (IOException e)
e.printStackTrace();
我们已经说完了beginObject()方法的源码,下面接着按示例代码的调用顺序来分析一下JsonReader的其它方法。
hasNext()
public boolean hasNext() throws IOException
int p = peeked;
if (p == PEEKED_NONE)
p = doPeek();
return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY;
在上一篇的最后,peeked被赋值为PEEKED_NONE,程序进入到doPeek()方法。
private int doPeek() throws IOException
int peekStack = stack[stackSize - 1];
if (peekStack == JsonScope.EMPTY_ARRAY)
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
else if (peekStack == JsonScope.NONEMPTY_ARRAY)
...
else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT)
stack[stackSize - 1] = JsonScope.DANGLING_NAME;
// Look for a comma before the next element.
if (peekStack == JsonScope.NONEMPTY_OBJECT)
...
int c = nextNonWhitespace(true);
switch (c)
case '"':
return peeked = PEEKED_DOUBLE_QUOTED_NAME;
case '\\'':
...
case '':
...
default:
...
else if (peekStack == JsonScope.DANGLING_NAME)
...
else if (peekStack == JsonScope.EMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.NONEMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.CLOSED)
...
int c = nextNonWhitespace(true);
switch (c)
case ']':
...
case ';':
case ',':
...
case '\\'':
...
case '"':
...
case '[':
return peeked = PEEKED_BEGIN_ARRAY;
case '':
return peeked = PEEKED_BEGIN_OBJECT;
default:
pos--; // Don't consume the first character in a literal value.
...
return peeked = PEEKED_UNQUOTED;
第2行,stackSize=2,peekStack=stack[1]=JsonScope.EMPTY_OBJECT。
第8行,stack[1]=JsonScope.DANGLING_NAME;
stack数组 | value |
---|---|
stack[0] | |
stack[1] | JsonScope.DANGLING_NAME |
第13行
int c = nextNonWhitespace(true);
private int nextNonWhitespace(boolean throwOnEof) throws IOException
char[] buffer = this.buffer;
int p = pos;
int l = limit;
while (true)
if (p == l)
...
int c = buffer[p++];
if (c == '\\n')
lineNumber++;
lineStart = p;
continue;
else if (c == ' ' || c == '\\r' || c == '\\t')
continue;
if (c == '/')
...
else if (c == '#')
...
else
pos = p;
return c;
...
直接看第10行
int c = buffer[p++];
int c = buffer[1]=34,在ANSCII码中34就是双引号,p=2。
0 | 1 |
---|---|
“ |
第24行,pos=p=2,将c作为返回值返回到doPeek()方法中。
doPeek()中运行到第16行
peeked = PEEKED_DOUBLE_QUOTED_NAME;
peeked的值 |
---|
PEEKED_DOUBLE_QUOTED_NAME |
程序回到hasNext()方法中
return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY
由于p=PEEKED_DOUBLE_QUOTED_NAME,所以hasNext()方法返回true。
nextName()
public String nextName() throws IOException
int p = peeked;
if (p == PEEKED_NONE)
p = doPeek();
String result;
if (p == PEEKED_UNQUOTED_NAME)
result = nextUnquotedValue();
else if (p == PEEKED_SINGLE_QUOTED_NAME)
result = nextQuotedValue('\\'');
else if (p == PEEKED_DOUBLE_QUOTED_NAME)
result = nextQuotedValue('"');
else
throw new IllegalStateException("Expected a name but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber());
peeked = PEEKED_NONE;
return result;
根据hasNext()方法可知,p=PEEKED_DOUBLE_QUOTED_NAME,程序运行到第12行,
nextQuotedValue('"');
private String nextQuotedValue(char quote) throws IOException
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
char[] buffer = this.buffer;
StringBuilder builder = new StringBuilder();
while (true)
int p = pos;
int l = limit;
/* the index of the first character not yet appended to the builder. */
int start = p;
while (p < l)
int c = buffer[p++];
if (c == quote)
pos = p;
builder.append(buffer, start, p - start - 1);
return builder.toString();
else if (c == '\\\\')
...
else if (c == '\\n')
...
...
第9行,start=p=2,之后进入while循环
int c = buffer[p++];
当p=6时,c=buffer[6]=34,也就是双引号,同时,p增加1,p=7。
builder.append(buffer, start, p - start - 1);
上面是第15行,p-start-1=7-2-1=4。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
“ | n | a | m | e | “ |
获取到的字符串就是2-6之间的字符拼接而成,也就是name。将name作为返回值返回到nextName()中,程序运行到第17行
peeked = PEEKED_NONE;
peeked的值 |
---|
PEEKED_NONE |
最终,nextName()将字符串name作为返回值返回。
nextString()
public String nextString() throws IOException
int p = peeked;
if (p == PEEKED_NONE)
p = doPeek();
String result;
if (p == PEEKED_UNQUOTED)
result = nextUnquotedValue();
else if (p == PEEKED_SINGLE_QUOTED)
result = nextQuotedValue('\\'');
else if (p == PEEKED_DOUBLE_QUOTED)
result = nextQuotedValue('"');
else if (p == PEEKED_BUFFERED)
result = peekedString;
peekedString = null;
else if (p == PEEKED_LONG)
result = Long.toString(peekedLong);
else if (p == PEEKED_NUMBER)
result = new String(buffer, pos, peekedNumberLength);
pos += peekedNumberLength;
else
throw new IllegalStateException("Expected a string but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber());
peeked = PEEKED_NONE;
return result;
第3行代码,p=PEEKED_NONE,程序运行第4行,代码再次进入doPeek()。
private int doPeek() throws IOException
int peekStack = stack[stackSize - 1];
if (peekStack == JsonScope.EMPTY_ARRAY)
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
else if (peekStack == JsonScope.NONEMPTY_ARRAY)
...
else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT)
...
else if (peekStack == JsonScope.DANGLING_NAME)
stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
// Look for a colon before the value.
int c = nextNonWhitespace(true);
switch (c)
case ':':
break;
case '=':
checkLenient();
if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>')
pos++;
break;
default:
throw syntaxError("Expected ':'");
else if (peekStack == JsonScope.EMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.NONEMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.CLOSED)
throw new IllegalStateException("JsonReader is closed");
int c = nextNonWhitespace(true);
switch (c)
case ']':
if (peekStack == JsonScope.EMPTY_ARRAY)
return peeked = PEEKED_END_ARRAY;
// fall-through to handle ",]"
case ';':
case ',':
...
case '\\'':
...
case '"':
if (stackSize == 1)
checkLenient();
return peeked = PEEKED_DOUBLE_QUOTED;
case '[':
return peeked = PEEKED_BEGIN_ARRAY;
case '':
return peeked = PEEKED_BEGIN_OBJECT;
default:
pos--; // Don't consume the first character in a literal value.
...
stackSize = 2,peekStack=stack[1]=JsonScope.DANGLING_NAME。
程序运行到第10行,stack[1]=JsonScope.NONEMPTY_OBJECT
stack数组 | value |
---|---|
stack[0] | |
stack[1] | JsonScope.NONEMPTY_OBJECT |
int c = nextNonWhitespace(true);
private int nextNonWhitespace(boolean throwOnEof) throws IOException
char[] buffer = this.buffer;
int p = pos;
int l = limit;
while (true)
if (p == l)
...
int c = buffer[p++];
if (c == '\\n')
lineNumber++;
lineStart = p;
continue;
else if (c == ' ' || c == '\\r' || c == '\\t')
continue;
if (c == '/')
...
else if (c == '#')
...
else
pos = p;
return c;
...
p=pos=7,l=limit=30,程序运行到第10行,c=buffer[7]=58,在ASCII码中是冒号:同时,p加1,p=8。
程序运行到第24行,pos=p=8,将c作为返回值返回到doPeek()方法中。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
“ | n | a | m | e | “ | : |
doPeek()方法中,运行到第12行,c=58,也就是冒号,程序运行第14行,15行,跳出switch语句。程序运行到第33行,再次运行nextNonWhitespace()方法。
private int nextNonWhitespace(boolean throwOnEof) throws IOException
char[] buffer = this.buffer;
int p = pos;
int l = limit;
while (true)
if (p == l)
...
int c = buffer[p++];
if (c == '\\n')
lineNumber++;
lineStart = p;
continue;
else if (c == ' ' || c == '\\r' || c == '\\t')
continue;
if (c == '/')
...
else if (c == '#')
...
else
pos = p;
return c;
...
第10行
int c = buffer[p++];
p=8,c=buffer[8]=34,也就是双引号,p加1,p=9。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
“ | n | a | m | e | “ | : | “ |
方法再次回到doPeek()方法,第33行
int c = nextNonWhitespace(true);
第45~49行,
case '"':
if (stackSize == 1)
checkLenient();
return peeked = PEEKED_DOUBLE_QUOTED;
stackSize=2,将PEEKED_DOUBLE_QUOTED赋值给peeked,方法将peeked返回。
peeked的值 |
---|
PEEKED_DOUBLE_QUOTED |
方法回到nextString()方法的第4行,继续往下运行,执行到第12行
result = nextQuotedValue('"');
private String nextQuotedValue(char quote) throws IOException
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
char[] buffer = this.buffer;
StringBuilder builder = new StringBuilder();
while (true)
int p = pos;
int l = limit;
/* the index of the first character not yet appended to the builder. */
int start = p;
while (p < l)
int c = buffer[p++];
if (c == quote)
pos = p;
builder.append(buffer, start, p - start - 1);
return builder.toString();
else if (c == '\\\\')
pos = p;
builder.append(buffer, start, p - start - 1);
builder.append(readEscapeCharacter());
p = pos;
l = limit;
start = p;
else if (c == '\\n')
lineNumber++;
lineStart = p;
builder.append(buffer, start, p - start);
pos = p;
if (!fillBuffer(1))
throw syntaxError("Unterminated string");
第9行,start=p=9,进入while循环,第11行
int c = buffer[p++];
builder.append(buffer, start, p - start - 1);
当p=17时,c=buffer[17]=34,也就是双引号,p加1,p=18。
p-start-1=18-9-1=8
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | l | y | “ |
将“王成wisely”这8个字符作为返回值返回到nextString()方法中的第12行,
result = nextQuotedValue('"');
result = “王成wisely”
之后,程序运行到第25行
peeked = PEEKED_NONE;
peeked的值 |
---|
PEEKED_NONE |
hasNext()
程序再次执行hasNext()方法
调用过程hasNext()–>doPeek(),如下
private int doPeek() throws IOException
int peekStack = stack[stackSize - 1];
if (peekStack == JsonScope.EMPTY_ARRAY)
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
else if (peekStack == JsonScope.NONEMPTY_ARRAY)
...
else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT)
stack[stackSize - 1] = JsonScope.DANGLING_NAME;
// Look for a comma before the next element.
if (peekStack == JsonScope.NONEMPTY_OBJECT)
int c = nextNonWhitespace(true);
switch (c)
case '':
return peeked = PEEKED_END_OBJECT;
case ';':
checkLenient(); // fall-through
case ',':
break;
default:
throw syntaxError("Unterminated object");
int c = nextNonWhitespace(true);
switch (c)
case '"':
return peeked = PEEKED_DOUBLE_QUOTED_NAME;
...
else if (peekStack == JsonScope.DANGLING_NAME)
...
else if (peekStack == JsonScope.EMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.NONEMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.CLOSED)
...
...
第11行,
int c = nextNonWhitespace(true);
c=44,也就是逗号。同时p=19。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | l | y | “ | , |
程序继续执行,运行到第23行
int c = nextNonWhitespace(true);
c=34,也就是双引号,同时p=20
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | l | y | “ | , | “ |
整个doPeek()方法运行完毕前,peeked被重新赋值为PEEKED_DOUBLE_QUOTED_NAME。
peeked的值 |
---|
PEEKED_DOUBLE_QUOTED_NAME |
程序执行回hasNext()方法,返回true。
nextName()
第二次运行,调用过程依旧,nextName()–>nextQuotedValue(‘”’)
private String nextQuotedValue(char quote) throws IOException
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
char[] buffer = this.buffer;
StringBuilder builder = new StringBuilder();
while (true)
int p = pos;
int l = limit;
/* the index of the first character not yet appended to the builder. */
int start = p;
while (p < l)
int c = buffer[p++];
if (c == quote)
pos = p;
builder.append(buffer, start, p - start - 1);
return builder.toString();
else if (c == '\\\\')
pos = p;
builder.append(buffer, start, p - start - 1);
builder.append(readEscapeCharacter());
p = pos;
l = limit;
start = p;
else if (c == '\\n')
lineNumber++;
lineStart = p;
builder.append(buffer, start, p - start);
pos = p;
if (!fillBuffer(1))
throw syntaxError("Unterminated string");
start=20,当p=23时,int c = buffer[23]=34,也就是双引号,同时p加1,p=24。
builder.append(buffer, start, p - start - 1);
p-start-1=24-20-1=3。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | |||||
l | y | “ | , | “ | a | g | e | “ |
最终nextName()方法返回age3个字符,并且将peeked重置为PEEKED_NONE。
peeked的值 |
---|
PEEKED_NONE |
nextInt()
public int nextInt() throws IOException
int p = peeked;
if (p == PEEKED_NONE)
p = doPeek();
int result;
if (p == PEEKED_LONG)
...
if (p == PEEKED_NUMBER)
...
else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED)
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\\'' : '"');
try
result = Integer.parseInt(peekedString);
peeked = PEEKED_NONE;
return result;
catch (NumberFormatException ignored)
// Fall back to parse as a double below.
else
throw new IllegalStateException("Expected an int but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber());
peeked = PEEKED_BUFFERED;
double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
result = (int) asDouble;
if (result != asDouble) // Make sure no precision was lost casting to 'int'.
throw new NumberFormatException("Expected an int but was " + peekedString
+ " at line " + getLineNumber() + " column " + getColumnNumber());
peekedString = null;
peeked = PEEKED_NONE;
return result;
方法进入调用了doPeek()方法
private int doPeek() throws IOException
int peekStack = stack[stackSize - 1];
if (peekStack == JsonScope.EMPTY_ARRAY)
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
else if (peekStack == JsonScope.NONEMPTY_ARRAY)
...
else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT)
...
else if (peekStack == JsonScope.DANGLING_NAME)
stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
// Look for a colon before the value.
int c = nextNonWhitespace(true);
switch (c)
case ':':
break;
case '=':
...
else if (peekStack == JsonScope.EMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.NONEMPTY_DOCUMENT)
...
else if (peekStack == JsonScope.CLOSED)
...
int c = nextNonWhitespace(true);
switch (c)
case ']':
...
case ';':
case ',':
...
case '\\'':
...
case '"':
if (stackSize == 1)
checkLenient();
return peeked = PEEKED_DOUBLE_QUOTED;
case '[':
return peeked = PEEKED_BEGIN_ARRAY;
case '':
return peeked = PEEKED_BEGIN_OBJECT;
default:
pos--; // Don't consume the first character in a literal value.
...
peekStack=stack[1]=JsonScope.JsonScope.DANGLING_NAME。
代码运行到第11行,为stack[1]赋值为JsonScope.NONEMPTY_OBJECT。
stack数组 | value |
---|---|
stack[0] | |
stack[1] | JsonScope.NONEMPTY_OBJECT |
程序运行到第13行,
int c = nextNonWhitespace(true);
获取到的c=58,也就是冒号:之后跳出switch语句再次运行了一个同样的语句,获得了一个c,c=34,也就是双引号。
然后为peeked重新赋值为PEEKED_DOUBLE_QUOTED,退出doPeek()方法
peeked的值 |
---|
PEEKED_DOUBLE_QUOTED |
代码回到nextInt中,继续运行第15行,最终又调用了nextQuotedValue(“)方法。
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\\'' : '"');
在nextQuotedValue()方法运行时,start=26,p=28时,c=34,也就是双引号,之后p加1,p=29,最终p-start-1=2,也就是24。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
l | y | “ | , | “ | a | g | e | “ | : | “ | 2 | 4 | “ |
之后为peeked赋值为PEEKED_NONE,
peeked的值 |
---|
PEEKED_NONE |
hasNext()
最后一次调用hasNext()方法。
hasNext()–>doPeek()–>nextNonWhitespace()
通过nextNonWhitespace方法获取到了一个右大括号,在doPeek()方法中重置peeked值为peeked = PEEKED_END_OBJECT。之后代码再返回到hasNext()中,返回false。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
“ | n | a | m | e | “ | : | “ | 王 | 成 | w | i | s | e | |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
l | y | “ | , | “ | a | g | e | “ | : | “ | 2 | 4 | “ |
peeked的值 |
---|
PEEKED_END_OBJECT |
endObject()
public void endObject() throws IOException
int p = peeked;
if (p == PEEKED_NONE)
p = doPeek();
if (p == PEEKED_END_OBJECT)
stackSize--;
peeked = PEEKED_NONE;
else
throw new IllegalStateException("Expected END_OBJECT but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber());
第7行时,将stackSize-1,变为了1。最后将peeked重置为PEEKED_NONE。
peeked的值 |
---|
PEEKED_NONE |
以上是关于Gson全解析之二:JsonReader的其它方法的主要内容,如果未能解决你的问题,请参考以下文章
我如何查看从 GSON JsonReader 收到了多少字节