代码之家  ›  专栏  ›  技术社区  ›  Shervin Asgari

使用array.copyof复制不同类型的数组时出现问题

  •  2
  • Shervin Asgari  · 技术社区  · 14 年前

    我试图创建一个方法,它几乎将任何东西作为参数,并返回一个带有分隔符的值的连接字符串表示。

    public static String getConcatenated(char delim, Object ...names) {
    String[] stringArray = Arrays.copyOf(names, names.length, String[].class); //Exception here
    return getConcatenated(delim, stringArray);
    }
    

    以及实际的方法

    public static String getConcatenated(char delim, String ... names) {
    if(names == null || names.length == 0)
        return "";
    
    StringBuilder sb = new StringBuilder();
    
    for(int i = 0; i < names.length; i++) {
        String n = names[i];
        if(n != null) {
            sb.append(n.trim());
            sb.append(delim);
        }
    }
    
    //Remove the last delim
    return sb.substring(0, sb.length()-1).toString();
    }
    

    我有以下JUnit测试:

    final String two = RedpillLinproUtils.getConcatenated(' ', "Shervin", "Asgari");
    Assert.assertEquals("Result", "Shervin Asgari", two); //OK
    
    final String three = RedpillLinproUtils.getConcatenated(';', "Shervin", "Asgari");
    Assert.assertEquals("Result", "Shervin;Asgari", three); //OK
    
    final String four = RedpillLinproUtils.getConcatenated(';', "Shervin", null, "Asgari", null);
    Assert.assertEquals("Result", "Shervin;Asgari", four); //OK
    
    final String five = RedpillLinproUtils.getConcatenated('/', 1, 2, null, 3, 4);
    Assert.assertEquals("Result", "1/2/3/4", five); //FAIL
    

    但是,最后一部分的测试失败,例外情况如下:

    java.lang.ArrayStoreException at java.lang.System.arraycopy(Native Method) at java.util.Arrays.copyOf(Arrays.java:2763)

    有人能找出错误吗?

    3 回复  |  直到 14 年前
        1
  •  2
  •   polygenelubricants    14 年前

    原因

    你不能把 Integer 在一个 String[] . 这就是为什么你会 ArrayStoreException . Arrays.copyOf 不转换。

    the API :

    T[] copyOf(U[] original, int newLength, Class< ? extends T[]> newType)

    投掷 : ArrayStoreException(阵列存储异常) -如果从复制的元素 original 不是可存储在类数组中的运行时类型 newType

    这个 ArrayStoreException API 有一个例子:

    引发以指示已尝试将错误类型的对象存储到对象数组中。例如,以下代码生成一个 ArrayStoreException(阵列存储异常) :

        Object x[] = new String[3];
        x[0] = new Integer(0);
    

    也见


    修复

    也就是说,你实际上不需要 String... 复制品 到A 字符串[ ] . 你的 getConcatenated 可以采取 Object... 它会很好的工作。

    public static String getConcatenated(char delim, Object... objs) {
        if(objs == null || objs.length == 0)
            return "";
    
        StringBuilder sb = new StringBuilder();
        for (Object o : objs) {
            if(o != null) {
                if (sb.length() > 0) sb.append(delim);
                sb.append(o.toString().trim());
            }
        }
        return sb.toString();
    }
    

    现在您可以执行以下操作:

        System.out.println(getConcatenated(';', "Shervin", null, "Asgari", null));
        // prints "Shervin;Asgari"
    
        System.out.println(getConcatenated('/', 1, 2, null, 3, 4));
        // prints "1/2/3/4"
    
        System.out.println(getConcatenated(':', "  ", null, "boo", "boo"));
        // prints "boo:boo"
    

    请注意,这符合原始代码中的预期规范,即 trim() 跳过 null .

        2
  •  6
  •   aioobe    14 年前

    既然你不能储存,就说 Integers ,在 String[] 数组,无法将对象数组复制到字符串数组中。你必须经历 .toString() 在每个对象上。

    例如,此解决方案可以工作:

    public static String concat(char delim, Object... objs) {
        if (objs == null || objs.length == 0) return "";
        StringBuilder sb = new StringBuilder();
        for (Object o : objs)
            sb.append(delim).append(o);
        return sb.substring(1);
    }
    

    作为瓦拉格斯的旁注,我怀疑你是否需要检查 objs == null . 编译器将从 concat(",", "a", "b", "c") 进入之内 concat(",", new Object[] {"a", "b", "c") 所以我看不出 objs 可能永远平等 null . ---GT;

        3
  •  1
  •   Thilo    14 年前

    你只能复制 String 进入一个 String[] .

    System#arraycopy Arrays#copyOf 不要进行任何类型转换,您必须将对象逐个转换为字符串,例如通过调用 String#valueOf (空安全版本 Object#toString )

    为什么不改变接受的方法呢 Object... 而不是 String... 并打电话 String.valueOf(obj) 在他们每个人身上。