一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java ArrayList.toArray(T[]) 方法的參數(shù)類型是 T 而不是 E的原因分析

Java ArrayList.toArray(T[]) 方法的參數(shù)類型是 T 而不是 E的原因分析

2020-04-16 14:07小米干飯 JAVA教程

這篇文章主要介紹了Java ArrayList.toArray(T[]) 方法的參數(shù)類型是 T 而不是 E的原因分析的相關資料,需要的朋友可以參考下

前兩天給同事做 code review,感覺自己對 Java 的 Generics 掌握得不夠好,便拿出 《Effective Java》1 這本書再看看相關的章節(jié)。在 Item 24:Eliminate unchecked warnings 這一節(jié)中,作者拿 ArrayList 類中的 public <T> T[] toArray(T[] a) 方法作為例子來說明如何對變量使用 @SuppressWarnings annotation。

ArrayList 是一個 generic class,它是這樣聲明的:

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

這個類的 toArray(T[] a) 方法是一個 generic method,它是這樣聲明和實現(xiàn)的:

?
1
2
3
4
5
6
7
8
9
10
@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 接口中聲明的。因為我們經(jīng)常通過 ArrayList 使用它,這里就用 ArrayList 作為例子了。

1 為什么聲明為不同類型?

我的問題是:為什么這個方法使用類型 T,而不使用 ArrayList 的類型 E ? 也就是說,這個方法為什么不聲明成這樣:

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

如果類型相同的話,在編譯期間就可以發(fā)現(xiàn)參數(shù)的類型錯誤。如果類型不同,很容易產(chǎn)生運行時錯誤。比如下面這段代碼:

?
1
2
3
4
5
6
//創(chuàng)建一個類型為 String 的 ArrayList
List<String> strList = new ArrayList<String>();
strList.add("abc");
strList.add("xyz");
//將當前的 strList 轉(zhuǎn)換成一個 Number 數(shù)組。注意,下面的語句沒有任何編譯錯誤。
Number[] numArray = strList.toArray(new Number[0]);

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

如果 toArray 方法使用類型 E 的話,語句2就會產(chǎn)生編譯錯誤。編譯錯誤怎么說也比運行時錯誤親切啊。并且,generics 的主要目的就是為了類型安全,把類型轉(zhuǎn)換錯誤(ClassCastException)消滅在編譯期間。這個方法卻反其道而行之。難道這是一個大 bug? Java 的 bug 俺碰上過,但這個地方出 bug 我還是不太敢相信。

上網(wǎng)一查,這個問題早已被討論過多次了2, 3, 4。

2 可以提高靈活性

這樣的聲明更靈活,可以把當前 list 中的元素轉(zhuǎn)換成一個更一般類型的數(shù)組。比如,當前 list 的類型是 Integer,我們可以把它的元素轉(zhuǎn)換成一個 Number 數(shù)組。

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

如果這個方法聲明成類型 E,上面的代碼就會有編譯錯誤。 看起來,該方法聲明成下面這樣會更合適:

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

不過, <T super E> 這樣的語法在 Java 中是不存在的。而且即使存在,對數(shù)組也不起作用。也正是因為這個原因,在使用這個方法時,即使 T 是 E 的父類,或 T 跟 E 相同,也不能完全避免 java.lang.ArrayStoreException 異常5, 6, 7 。請看下面兩段代碼。第一段代碼中 T 是 E 的父類,第二段代碼中 T 和 E 一樣。這兩段代碼都會拋出異常。

代碼一:

?
1
2
3
4
5
6
7
8
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);

代碼二:

?
1
2
3
4
5
6
7
8
9
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[] 是所有數(shù)組的父類。

這個帖子8里舉了個例子,說明即使這個方法的類型聲明成 E 也不能避免 ArrayStoreException 異常。

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

?
1
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)就出現(xiàn)了9。那時它被聲明稱這樣:

?
1
Javapublic Object[] toArray(Object[] a)

Generics 出現(xiàn)后,許多類和方法就變成 generic 的了。這個方法也隨大流聲明成這樣:

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

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

4 多啰嗦兩句

這個方法需要一個數(shù)組參數(shù)。如果這個數(shù)組的 length 大于或等于當前 list 的 size,list 中的元素就會存儲到這個數(shù)組當中;如果這個數(shù)組的 length 小于當前 list 的 size,就會創(chuàng)建一個新的數(shù)組,并把當前 list 中的元素存入到這個新創(chuàng)建的數(shù)組中。為提高效率,如果可能,傳入的數(shù)組的 length 要大于或等于 list 的 size,以避免該方法新建數(shù)組。

?
1
2
3
4
5
6
7
List<Integer> intList = new ArrayList<Integer>();
intList.add();
intList.add();
//傳入一個數(shù)組,它的長度為
Number[] numArray = intList.toArray(new Number[]); //語句
//傳入一個數(shù)組,它的長度與 intList 的長度相等
Number[] numArray = intList.toArray(new Number[intList.size()]); //語句

另外,作為參數(shù)的數(shù)組不能為 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

以上內(nèi)容是小編給大家介紹的Java ArrayList.toArray(T[]) 方法的參數(shù)類型是 T 而不是 E的原因分析,希望對大家有所幫助!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产高清路线一路线二2022 | 国产在线三级 | 秋葵视频成人 | 贰佰麻豆剧果冻传媒一二三区 | 亚洲精品第五页中文字幕 | 大胸孕妇孕交pregnantsex 大象视频污 | 国产精品视频人人做人人爱 | 久久国产乱子伦免费精品 | 日本福利视频网站 | 女女性恋爱免费 | 91麻豆精品国产片在线观看 | 色播影音先锋 | 久久国产主播福利在线 | 国产高清ujzzujzz | 二区三区视频 | 成人免费观看在线视频 | a网在线| 天天色天天色天天色 | 亚洲 欧美 国产 日韩 字幕 | 欧美一区二区三区成人看不卡 | 国产资源中文字幕 | 国产精品亚洲精品日韩已满 | 亚洲国产精品免费在线观看 | 青草视频免费观看在线观看 | 亚洲精选在线观看 | 雪恋电影完整版免费观看 | 亚洲午夜天堂 | 99re这里只有精品在线观看 | 日韩欧美推理片免费在线播放 | 福利片福利一区二区三区 | 午夜家庭影院 | 亚洲美洲国产日产 | 娇妻在床上迎合男人 | 精品国产剧情在线观看 | 98精品全国免费观看视频 | 免费一看一级欧美 | 99福利影院| 欧美一级视频免费观看 | 亚洲国产99在线精品一区二区 | 久久成人a毛片免费观看网站 | 明星ai人脸替换脸忘忧草 |