程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析

Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析

編輯:關於JAVA

Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析。本站提示廣大學習愛好者:(Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析正文


前兩天給同事做 code review,感到本身對 Java 的 Generics 控制得不敷好,便拿出 《Effective Java》1 這本書再看看相干的章節。在 Item 24:Eliminate unchecked warnings 這一節中,作者拿 ArrayList 類中的 public <T> T[] toArray(T[] a) 辦法作為例子來講明若何對變量應用 @SuppressWarnings annotation。

ArrayList 是一個 generic class,它是如許聲明的:

Javapublic class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

這個類的 toArray(T[] a) 辦法是一個 generic method,它是如許聲明和完成的:

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

這個辦法現實上是在 Collection 接口中聲明的。由於我們常常經由過程 ArrayList 應用它,這裡就用 ArrayList 作為例子了。

1 為何聲明為分歧類型?

我的成績是:為何這個辦法應用類型 T,而不應用 ArrayList 的類型 E ? 也就是說,這個辦法為何不聲明成如許:

Javapublic E[] toArray(E[] a);

假如類型雷同的話,在編譯時代便可以發明參數的類型毛病。假如類型分歧,很輕易發生運轉時毛病。好比上面這段代碼:

//創立一個類型為 String 的 ArrayList
List<String> strList = new ArrayList<String>();
strList.add("abc");
strList.add("xyz");
//將以後的 strList 轉換成一個 Number 數組。留意,上面的語句沒有任何編譯毛病。
Number[] numArray = strList.toArray(new Number[0]);

運轉下面的代碼, Line 6 會拋出 java.lang.ArrayStoreException 異常。

假如 toArray 辦法應用類型 E 的話,語句2就會發生編譯毛病。編譯毛病怎樣說也比運轉時毛病親熱啊。而且,generics 的重要目標就是為了類型平安,把類型轉換毛病(ClassCastException)祛除在編譯時代。這個辦法卻反其道而行之。豈非這是一個年夜 bug? Java 的 bug 俺碰上過,但這個處所出 bug 我照樣不太敢信任。

上彀一查,這個成績早已被評論辯論過量次了2, 3, 4。

2 可以進步靈巧性

如許的聲明更靈巧,可以把以後 list 中的元素轉換成一個更普通類型的數組。好比,以後 list 的類型是 Integer,我們可以把它的元素轉換成一個 Number 數組。

List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
Number[] numArray = intList.toArray(new Number[0]);

假如這個辦法聲明成類型 E,下面的代碼就會有編譯毛病。 看起來,該辦法聲明成上面如許會更適合:

Javapublic <T super E> T[] toArray(T[] a);

不外, <T super E> 如許的語法在 Java 中是不存在的。並且即便存在,對數組也不起感化。也恰是由於這個緣由,在應用這個辦法時,即便 T 是 E 的父類,或 T 跟 E 雷同,也不克不及完整防止 java.lang.ArrayStoreException 異常5, 6, 7 。請看上面兩段代碼。第一段代碼中 T 是 E 的父類,第二段代碼中 T 和 E 一樣。這兩段代碼都邑拋出異常。

代碼一:

List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2); 
Float[] floatArray = new Float[2];
//Float 是 Number 的子類,所以 Float[] 是 Number[] 的子類
Number[] numArray = floatArray;
//上面的語句會拋出 ArrayStoreException 異常
numArray = intList.toArray(numArray);

代碼二:

List<Number> intList = new ArrayList<Number>();
//List 的類型是 Number。但 Number 是籠統類,只能存它的子類的實例
intList.add(new Integer());
intList.add(new Integer()); 
Float[] floatArray = new Float[];
//Float 是 Number 的子類,所以 Float[] 是 Number[] 的子類
Number[] numArray = floatArray;
//上面的語句會拋出 ArrayStoreException 異常
numArray = intList.toArray(numArray);

下面的異常都是由這個現實形成的:假如 A 是 B 的父類,那末 A[] 是 B[] 的父類。Java 中一切的類都繼續自 Object,Object[] 是一切數組的父類。

這個帖子8裡舉了個例子,解釋即便這個辦法的類型聲明成 E 也不克不及防止 ArrayStoreException 異常。

該辦法的文檔中也提到了這個異常:

ArrayStoreException if the runtime type of the specified array is not a supertype of the runtime type of every element in this list.

3 可以與 Java 1.5 之前的版本兼容

這個辦法在 Java 引入 Generics 之前(JDK1.5 中引入了 Generics)就湧現了9。那時它被聲明稱如許:

Javapublic Object[] toArray(Object[] a)

Generics 湧現後,很多類和辦法就釀成 generic 的了。這個辦法也隨年夜流聲明成如許:

Javapublic <T> T[] toArray(T[] a)

如許聲明可以與 Java 1.5 之前的版本兼容10。

4 多煩瑣兩句

這個辦法須要一個數組參數。假如這個數組的 length 年夜於或等於以後 list 的 size,list 中的元素就會存儲到這個數組傍邊;假如這個數組的 length 小於以後 list 的 size,就會創立一個新的數組,並把以後 list 中的元素存入到這個新創立的數組中。為進步效力,假如能夠,傳入的數組的 length 要年夜於或等於 list 的 size,以免該辦法新建數組。

List<Integer> intList = new ArrayList<Integer>();
intList.add();
intList.add();
//傳入一個數組,它的長度為 
Number[] numArray = intList.toArray(new Number[]); //語句
//傳入一個數組,它的長度與 intList 的長度相等
Number[] numArray = intList.toArray(new Number[intList.size()]); //語句

別的,作為參數的數組不克不及為 null ,不然的話會拋出 NullPointerException 異常。

Footnotes:

1
Effective Java (2nd Edition)
2
Link
3
Link
4
Link
5
Link
6
Link
7
Link
8
Link
9
Link
10
Link
Created: 2016-04-06 Wed 21:14
Emacs 24.5.1 (Org mode 8.2.10)
Validate

以上內容是小編給年夜家引見的Java ArrayList.toArray(T[]) 辦法的參數類型是 T 而不是 E的緣由剖析,願望對年夜家有所贊助!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved