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

json

阅读原文请访问我的博客BrightLoong's Blog
之前在使用 alibaba的fastjson做数组的相关转换操作的时候遇到一些问题,这里把遇到的问题以及如何解决的记录如下。

一. 转换过程中的问题

话不多说,先上代码。

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());
    }
}

输出结果是:

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

同样先上代码:

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]);
    }
}

输出结果是:

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,具体使用见上述的代码。

三. 如何解决转换问题

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

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","5","6"]]
class com.alibaba.fastjson.JSONArray
class [[Ljava.lang.String;
true

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 1.在C/C++中实现本地方法 生成C/C++头文件之后,你就需要写头文件对应的本地方法。注意:所有的本地方法的第...
    JayQiu阅读 2,320评论 0 3
  • Jni数据类型 Jni方法 来自 http://blog.chinaunix.net/uid-22028680-i...
    FlyDragonInSky阅读 897评论 0 0
  • 数据类型 在JavaScript中,包含6种数据类型,字符串(string),数值(number),布尔值(boo...
    李高尚阅读 206评论 0 0
  • 古风故事 正文 -01- 她,死了。 入土时分,只带入了一瓣花香。 但她于世,却留下了一片流言。 陆家庭院花开否?...
    路人葵阅读 802评论 49 30