使用Generic Arrays的ArrayList转换ArrayList.toArray()

时间:2011-01-19 14:34:24

标签: java arrays generics casting arraylist

一个很难回答放弃所有希望的难题。我想做一个 函数,但是让ArrayList.toArray()返回我想要的类型时遇到问题。

这是演示我的问题的最小例子:

public static <T> T[] test(T one, T two) {
    java.util.List<T> list = new ArrayList<T>();
    list.add(one);
    list.add(two);
    return (T[]) list.toArray();
}

通常情况下,我可以使用(T[]) list.toArray(new T[0])形式,但有两个额外的困难:

  1. 由于协方差规则我无法对数组进行类型转换,(T[]) myObjectArray给出ClassCastException
  2. 您无法创建泛型类型的新实例,这意味着我无法实例new T[]。我也不能在ArrayList的某个元素上使用克隆或尝试获取它的类。
  3. 我一直在尝试使用以下调用获取一些信息:

    public static void main(String[] args) {
       System.out.println(test("onestring", "twostrings"));
    }
    

    结果是[Ljava.lang.Object;@3e25a5形式,表明返回的类型转换无效。奇怪的是:

    public static void main(String[] args) {
        System.out.println(test("onestring", "twostrings").getClass());
    }
    

    回来了:

    Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
    at patchLinker.Utilities.main(Utilities.java:286)
    

    所以我最好的猜测是它认为它是一个明智的String数组标签,但内部是一个Object数组,任何访问尝试都会带来不一致性。

    如果有人能找到解决这个问题的方法(因为我拒绝了两个正常的解决方法),我会非常感激。

    K.Barad JDK1.6


    修改


    感谢Peter Lawrey解决最初的问题。现在的问题是如何使解决方案适用于我不太重要的例子:

    public static <T> T[] unTreeArray(T[][] input) {
        java.util.List<T> outList = new ArrayList<T>();
        java.util.List<T> tempList;
        T[] typeVar;
        for (T[] subArray : input) {
            tempList = java.util.Arrays.asList(subArray);
            outList.addAll(tempList);
        }
        if (input.length > 0) {
            typeVar = input[0];
        } else {
            return null;
        }
        return (T[]) outList.toArray((T[]) java.lang.reflect.Array.newInstance(typeVar.getClass(),outList.size()));
    }
    
    public static void main(String[] args) {
        String[][] lines = { { "111", "122", "133" }, { "211", "222", "233" } };
        unTreeArray(lines);
    }
    

    目前的结果是

    Exception in thread "main" java.lang.ArrayStoreException
    at java.lang.System.arraycopy(Native Method)
    at java.util.ArrayList.toArray(Unknown Source)
    at patchLinker.Utilities.unTreeArray(Utilities.java:159)
    at patchLinker.Utilities.main(Utilities.java:301)
    

    我还在做一些测试,看看能否获得比这更有用的信息,但目前我不知道从哪里开始。我会在收到的时候添加更多信息。

    K.Barad


    编辑2


    现在有更多信息。我试图手动构建数组并以元素方式传输项目,因此我将类型转换为T,而不是T []。我发现了一个有趣的结果:

    public static <T> T[] unTreeArray(T[][] input) {
        java.util.List<T> outList = new ArrayList<T>();
        java.util.List<T> tempList;
        T[] outArray;
        for (T[] subArray : input) {
            tempList = java.util.Arrays.asList(subArray);
            outList.addAll(tempList);
        }
        if (outList.size() == 0) {
            return null;
        } else {
            outArray = input[0];// use as a class sampler
            outArray =
                    (T[]) java.lang.reflect.Array.newInstance(outArray.getClass(), outList.size());
            for (int i = 0; i < outList.size(); i++) {
                System.out.println(i + "  " + outArray.length + "   " + outList.size() + "   "  + outList.get(i));
                outArray[i] = (T) outList.get(i);
            }
            System.out.println(outArray.length);
            return outArray;
        }
    }
    

    我仍然得到以下输出:

    0  6   6   111
    Exception in thread "main" java.lang.ArrayStoreException: java.lang.String
    at patchLinker.Utilities.unTreeArray(Utilities.java:291)
    at patchLinker.Utilities.main(Utilities.java:307)
    

    这是否意味着即使您设法间接创建一个,也无法写入T[]

3 个答案:

答案 0 :(得分:4)

toArray()总是返回一个对象数组。

要返回特定类型的数组,您需要使用toArray(Object [])。

要为数组参数提供正确的类型,您需要使用特定的类,或者在这种情况下使用反射。

 return (T[]) list.toArray(Array.newInstance(one.getClass(), list.size()));

答案 1 :(得分:2)

第二个代码示例的问题是由于T[] typeVar引起的:输入是一个两个暗淡的数组,因此input[0]将返回一个暗淡的数组(String [],而不是String,如预期的那样。)

如果您要将List<T>转换为T[],则需要T typeVar

修复它:

public static <T> T[] unTreeArray(T[][] input) {
    java.util.List<T> outList = new ArrayList<T>();
    java.util.List<T> tempList;

    if (input.length == 0) {
        return null;
    }


    T typeVar=null;
    for (T[] subArray : input) {
        if(typeVar==null && subArray.length>0) {
            typeVar=subArray[0];
        }
        tempList = java.util.Arrays.asList(subArray);
        outList.addAll(tempList);
    }

    return outList.toArray((T[]) Array.newInstance(typeVar.getClass(),0));
}

public static void main(String[] args) {
    String[][] lines = { { "111", "122", "133" }, { "211", "222", "233" } };
    String[] result=unTreeArray(lines);

    System.out.println(result);

    System.out.println(result.getClass());

        //added for completion:
    System.out.println( Arrays.toString(result));

}

结果输出:

  

[Ljava.lang.String; @ 5a405a4 class
  [Ljava.lang.String;
  [111,122,133,211,222,233]

答案 2 :(得分:1)

您无法创建泛型类型参数的数组。原因很简单,java通常在运行时擦除泛型类型信息,因此运行时不知道T是什么(当T是泛型类型参数时)。

因此,解决方案是在运行时实际获取类型信息。通常这是通过传递Class<T> type参数来完成的,但在这种情况下,您可以避免这样做:

@ peter的回答看起来不错,我会用它:)。

return (T[]) list.toArray(Array.newInstance(one.getClass(), list.size()));