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

雖然如此,但因此函數的行爲就可能產生了歧義,對調用者還是會產生誤導的,我認爲這終歸還應該是個問題的,如能解決是最好的了。

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