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

时间:2010-05-21 13:16:50

标签: java arrays

我正在尝试创建一个几乎将任何东西作为参数的方法,并使用一些分隔符返回值的连接字符串表示。

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 个答案:

答案 0 :(得分:6)

由于您无法在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);
}

作为关于varargs的旁注;我怀疑你是否需要检查objs == null。编译器会将concat(",", "a", "b", "c")的调用转换为concat(",", new Object[] {"a", "b", "c"),因此我无法看到objs如何等于null。 - &GT;

答案 1 :(得分:2)

原因

您无法将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...Arrays.copyOfString[]。您的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 :(得分:1)

您只能将String复制到String[]

System#arraycopyArrays#copyOf不进行任何类型转换,您必须自己逐个将对象转换为字符串,例如调用String#valueOf(null安全版本的Object#toString)。

为什么不将方法更改为接受Object...而不是String...,并在每个方法上调用String.valueOf(obj)