Java编程下的asList()

package cn.sunzn.array;

import java.io.PrintStream;
import java.util.Arrays;
import org.junit.Test;

public class ArraysAsList {

    public static void main(String[] args) {

        /**
         * 最近在用 Arrays 的 asList() 生成的 List 时,List 元素的个数时而不正确。
         * 经多次测试,只要传递的基本类型的数组,生成 List 的元素个数均为1 传递对象数组,元素个数正确
         */

        char[] arrChar = { 'a', 'b' };
        Arrays.asList(arrChar).size();                 // 结果为1;

        int[] arrInt = { 1, 2, 4 };
        Arrays.asList(arrInt).size();                 // 结果为1;

        String[] arrString = { "A", "B", "C" };
        Arrays.asList(arrString).size();             // 结果为3;

    }

    /**
     * 跟源码: 
     * public static <T> List<T> asList(T... a) {
     *        return new ArrayList<T>(a); 
     * }
     * 
     * 继续跟,Arrays的私有内部类ArrayList (没搞明白,为什么这里也起名为 ArrayList)
     * 
     * private final E[] a;
     * 
     * ArrayList(E[] array) {
     *       if (array==null)
     *           throw new NullPointerException();
     *     a = array; 
     * }
     * 
     * public int size() {
     *       return a.length;
     * }
     */
    
}

/**
 * 发现问题出在java5 的可变参数上。于是写了demo,测试。
 */
class TestArray {
    PrintStream out = System.out;
    @Test
    public void array() {
        char[] arrc = { 'a', 'b', 'c', 'd', 'e' };
        out.println("传递char数组:");
        print(arrc);
        out.println("直接传递:");
        print('a', 'b', 'c', 'd', 'e');
        out.println("----------------------------");

        int[] arri = { 1, 2, 3, 4, 5 };
        out.println("传递int数组:");
        print(arri);
        out.println("直接传递:");
        print(1, 2, 3, 4, 5);
        out.println("----------------------------");

        Integer[] arrInt = { 1, 2, 3, 4, 5};
        out.println("传递Integer数组:");
        /**[Notice]
         * The argument of type Integer[] should explicitly 
         * be cast to Object[] for the invocation of the 
         * varargs method print(Object...) from type TestArray. 
         * It could alternatively be cast to Object for 
         * a varargs invocation
         */
        print((Object)arrInt);
        out.println("直接传递:");
        print(1, 2, 3, 4, 5);
        out.println("----------------------------");

        String[] arrs = { "a", "b", "c", "d", "e" };
        out.println("传递String数组:");
        /**[Notice]
         * The argument of type String[] should explicitly
         * be cast to Object[] for the invocation of the 
         * varargs method print(Object...) from type TestArray. 
         * It could alternatively be cast to Object for 
         * a varargs invocation
         */
        print((Object)arrs);
        out.println("直接传递:");
        print('a', 'b', 'c', 'd', 'e');
        out.println("----------------------------");
    }

    public void print(Object... arr) {
        out.print("内容:" + Arrays.toString(arr));
        out.println("\t\t数组长度:" + arr.length + " ");
    }
}

/******************************************************************
传递char数组:
内容:[[C@4b1e0ac]                数组长度:1 
直接传递:
内容:[a, b, c, d, e]        数组长度:5 
----------------------------
传递int数组:
内容:[[I@3a153e9c]                数组长度:1 
直接传递:
内容:[1, 2, 3, 4, 5]        数组长度:5 
----------------------------
传递Integer数组:
内容:[1, 2, 3, 4, 5]        数组长度:5 
直接传递:
内容:[1, 2, 3, 4, 5]        数组长度:5 
----------------------------
传递String数组:
内容:[a, b, c, d, e]        数组长度:5 
直接传递:
内容:[a, b, c, d, e]        数组长度:5 
----------------------------
******************************************************************/

/**
 * java 5 可变参数,直接传递值与传递数组处理的机制不太相同。如果直接传递
 * 数组,基本类型数组将被视为一个对象而不会被解析成数组,如果直接传递参数
 * 将能正常解析。因此传递基本类型数组时强烈建议转为其封装类对象的数组
 * int ->Integer ,long->Long …………。(未对其封装)
 */

/** 这样写就很清楚了吧
package cn.sunzn.array;

import java.util.Arrays;
import java.util.List;

public class Test {
    public static void main(String[] args) {
          int[] intArray = {1,2,3};
          List<int[]> myList = Arrays.asList(intArray);
          System.out.println(myList.size());
          System.out.println(myList.get(0).length);
        }
}
*/

/******************************************************************
 * 输出结果为:1 3
******************************************************************/

/******************************************************************
 * 所以定义就不难理解了
 * public static <T> List<T> asList(T... a) {
 *        return new ArrayList<T>(a);
 * }
 * 这个 T 必须是对象类型。好比我们不能 new ArrayList<int> 只能 new ArrayList<Integer> 
******************************************************************/

==========================================================


jdk 1.4对java.util.Arrays.asList的定义,函数参数是Object[]。所以,在1.4中asList()并不支持基本类型的数组作参数。

jdk 1.5中,java.util.Arrays.asList的定义,函数参数是Varargs, 采用了泛型实现。同时由于autoboxing的支持,使得可以支持对象数组以及基本类型数组。

但在使用过程中发现jdk1.5中存在一个BUG。就是等参数为基本类型的数组时,函数的行为发生了变异:它不是把这个数组转换为List,而是把这个数组整体作为返回List中的第一个元素,要取得转换后的结果,得首先get(0)才行。

到网上google了一下,Sun好像认为这并不是个问题。理由如下:
Arrays.asList is now a vararg method, and the behavior is as intended:  asList(int[] ...)
The Java generics implementation does not support non-reference type parameters.
This is all standard Java 5.0 stuff.
URL:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6353471

虽然如此,但因此函数的行为就可能产生了歧义,对调用者还是会产生误导的,我认为这终归还应该是个问题的,如能解决是最好的了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章