BrightLoong's Blog

数组->JSON字符串->数组过程中的问题

json

之前在使用 alibaba的fastjson做数组的相关转换操作的时候遇到一些问题,这里把遇到的问题以及如何解决的记录如下。

一. 转换过程中的问题

话不多说,先上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class JsonTest {
public static void main(String[] args) {
//创建一个String数组
String[][] stringArray = new String[][]{{"1","2","3"},{"4","5","6"}};
//使用fastjson转为json字符串
String jsonString = JSON.toJSONString(stringArray);
System.out.println(jsonString);

//解析json字符串后输出class发现是jsonArray的。
Object array = JSON.parse(jsonString);
System.out.println(array.getClass());
}
}

输出结果是:

1
2
3
Before class:class [[Ljava.lang.String;
[["1","2","3"],["4","5","6"]]
After class:class com.alibaba.fastjson.JSONArray

遇到的问题如上,把一个数组转为json字符串后,再使用用JSON.parse()转换回来,获取到的class类型却是JSONArray的。

当然你也可以用很简单的办法把他给转换成需要的String二维数组。不过我的需求是:

  1. 只知道是个数组,知道到数组的原始Class类型(如果是String[][]知道是String.class)
  2. 不知道是几维数组,也不知道最开始传入的数组的长度
  3. 在拿到从Json字符串转换回来的object的时候,必须要使用原始类型(比如是String[][],那么转换回来的object,使用object.getClass()应该得到[[Ljava.lang.String),否则无法使用。

为了解决上述问题,在网上查阅各种资料无果,最后突然想到查询数组的反射,找到了java.lang.reflect.Array这个包,下面对这个包里面的一些使用做一个简单的介绍。

二. 关于java.lang.reflect.Array

同样先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class ArrayTest {

/**
* 创建一维数组.
* @param cls 数组基本类型Class
* @param length 创建数组长度
* @return 创建的数组
*/
public static Object creatOneDimArray(Class cls, int length) {
return Array.newInstance(cls, length);
}

/**
* 创建多维数组.
* @param cls 数组基本类型Class
* @param dims 维度信息
* @return 创建的数组
*/
public static Object creatMultiDimsArray(Class cls, int[] dims) {
return Array.newInstance(cls, dims);
}

/**
* 获取数组的长度和class信息.
* @param array 使用Array.newInstance()创建的array
* @return 长度和class信息
*/
public static String getArrayInfo(Object array) {
Class cls = array.getClass();
//只会返回第一维度的长度,比如String[1][2][3]返回1,String[3][4]返回3
int length = Array.getLength(array);
return "CLASS:" + cls + "-----" + "LENGTH:" + length;
}

public static void main(String[] args) {
//创建长度为10的一维String数组
Object oneArray = creatOneDimArray(String.class, 10);
System.out.println(getArrayInfo(oneArray));

//创建一个[2,3,4]的二维String数组
int[] dims = new int[]{2,3,4};
Object threeArray = creatMultiDimsArray(String.class,dims);
System.out.println(getArrayInfo(threeArray));

//**************************
//* 数组赋值操作 *
//**************************

//---------1.强制转换赋值
((String[])oneArray)[1] = "hello";
((String[])oneArray)[9] = " world";
System.out.println(((String[])oneArray)[1] + ((String[])oneArray)[9]);

((String[][][])threeArray)[1][2][3] = "hello";
((String[][][])threeArray)[0][1][3] = " java";
System.out.println(((String[][][])threeArray)[1][2][3] + ((String[][][])threeArray)[0][1][3]);

//--------2.使用Array.set()进行赋值操作
//使用Array.get()可以获取到下一维的值,比如三维的获取到二维
//获取三维中index=1的二维数组,Strign[1][][]。
Object two = Array.get(threeArray,1);
//从输出可以看到获取到的是一个二维数组
System.out.println("CLASS:" + two.getClass());
//对String[1][0][]赋值
Array.set(two,0,new String[]{"this"," is"," a"," test"});
System.out.println(((String[][][])threeArray)[1][0][0] + ((String[][][])threeArray)[1][0][1]
+ ((String[][][])threeArray)[1][0][2] + ((String[][][])threeArray)[1][0][3]);

//再获取一维String[1][1][]
Object one = Array.get(two,1);
System.out.println("CLASS:" + one.getClass());

Array.set(one,0,"my");
Array.set(one,1," name");
Array.set(one,2," is");
Array.set(one,3," brightloong");
System.out.println(((String[][][])threeArray)[1][1][0] + ((String[][][])threeArray)[1][1][1]
+ ((String[][][])threeArray)[1][1][2] + ((String[][][])threeArray)[1][1][3]);
}
}

输出结果是:

1
2
3
4
5
6
7
8
CLASS:class [Ljava.lang.String;-----LENGTH:10
CLASS:class [[[Ljava.lang.String;-----LENGTH:2
hello world
hello java
CLASS:class [[Ljava.lang.String;
this is a test
CLASS:class [Ljava.lang.String;
my name is brightloong

这里已经在上述代码中做了大部分的注释,这里也不在详细介绍,主要说一下几个方法的作用。

  • Array.newInstance(Class<?> componentType, int length)Array.newInstance(Class<?> componentType, int... dimensions)第一个用于创建传入类型的长度为length的一维数组,第二个可以用于创建传入类型的多维数组,维度和长度由传入的第二个参数决定。
  • Array.get(Object array, int index)用于获取传入的数组array的index下的内容。
  • Array.set(Object array, int index, Object value)用于对传入的数组array的index进行赋值,赋值为value,具体使用见上述的代码。

三. 如何解决转换问题

在具备了以上的了解后,再来解决所遇到的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class JsonArrayToArray {
public static void main(String[] args) {
//创建一个String数组
String[][] stringArray = new String[][]{{"1","2","3"},{"4","5","6"}};
//使用fastjson转为json字符串
String jsonString = JSON.toJSONString(stringArray);
System.out.println(jsonString);

//解析json字符串后输出class发现是jsonArray的。
Object array = JSON.parse(jsonString);
System.out.println(array.getClass());

Object realArray = null;
try {
realArray = getArrayInstanceByClassAndArg(String.class, array);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
parseJsonArray(array, realArray);
System.out.println(realArray.getClass());
System.out.println(realArray.getClass().equals(String[][].class));
}

/**
* 解析jsonArray还原为最开始的数组
* @param o 解析后的类型是jsonArray的参数
* @param array 实际要组装的数组
*/
private static void parseJsonArray(Object o, Object array) {
parseJsonArray(o, array, null, 0);
}

/**
* 利用递归调用,解析jsonArray还原为最开始的数组
* @param o 解析后的类型是jsonArray的参数
* @param array 实际要组装的数组
* @param lastArray 上一个array
* @param index index
*/
private static void parseJsonArray(Object o, Object array, Object lastArray, int index) {
JSONArray tempArray;
//如果class不是JSONArray,使用Array.set()赋值
if (!o.getClass().equals(JSONArray.class)) {
Array.set(lastArray,index , o);
return;
}
//如果是JSONArray,继续继续循环递归调用
tempArray = (JSONArray)o;
for (int i = 0; i < tempArray.size(); i++) {
Object arrayTemp = Array.get(array, i);
parseJsonArray(tempArray.get(i), arrayTemp, array, i);
}
}

/**
* 根据class和传入的解析后的类型是jsonArray的参数,获取对应维度和大小的数组
* @param cls Class
* @param argValue 解析后的类型是jsonArray的参数
* @return 返回数组
* @throws ClassNotFoundException 异常
*/
private static Object getArrayInstanceByClassAndArg(Class cls, Object argValue)
throws ClassNotFoundException {
Object temp = argValue;
JSONArray tempArray;
List<Integer> dimsInf = new ArrayList<Integer>();
//获取jsonArray对应的数组维度和长度
while (temp.getClass().equals(JSONArray.class)) {
tempArray = (JSONArray)temp;
dimsInf.add(tempArray.size());
temp = tempArray.get(0);
}
int[] dims = new int[dimsInf.size()];
for (int i = 0; i < dimsInf.size(); i++) {
dims[i] = dimsInf.get(i);
}
//返回对应的数组
return Array.newInstance(cls, dims);
}
}

输出结果是:

1
2
3
4
[["1","2","3"],["4","5","6"]]
class com.alibaba.fastjson.JSONArray
class [[Ljava.lang.String;
true

可以看到最后被将转换后的Class为JSONArray的结果在转换为最初的数组类型,String[][],由最后realArray.getClass().equals(String[][].class)返回结果true也可以得到确实转换正确了。具体的解析方法可以看上面的parseJsonArray()方法。

坚持原创技术分享,您的支持将鼓励我继续创作!