国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

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

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java 泛型總結(二):泛型與數組

Java 泛型總結(二):泛型與數組

2020-08-31 14:23然則 Java教程

數組與泛型的關系還是有點復雜的,Java 中不允許直接創建泛型數組。本文分析了其中原因并且總結了一些創建泛型數組的方式。具有很好的參考價值。下面跟著小編一起來看下吧

簡介

上一篇文章介紹了泛型的基本用法以及類型擦除的問題,現在來看看泛型數組的關系。數組相比于Java 類庫中的容器類是比較特殊的,主要體現在三個方面:

  • 數組創建后大小便固定,但效率更高
  • 數組能追蹤它內部保存的元素的具體類型,插入的元素類型會在編譯期得到檢查
  • 數組可以持有原始類型 ( int,float等 ),不過有了自動裝箱,容器類看上去也能持有原始類型了

那么當數組遇到泛型會怎樣? 能否創建泛型數組呢?這是這篇文章的主要內容。

這個系列的另外兩篇文章:

泛型數組

如何創建泛型數組

如果有一個類如下:

java" id="highlighter_77334">
?
1
2
3
class Generic<T> {
 
}

如果要創建一個泛型數組,應該是這樣: Generic<Integer> ga = new Generic<Integer>[]  不過行代碼會報錯,也就是說不能直接創建泛型數組。

那么如果要使用泛型數組怎么辦?一種方案是使用 ArrayList,比如下面的例子:

?
1
2
3
4
5
public class ListOfGenerics<T> {
 private List<T> array = new ArrayList<T>();
 public void add(T item) { array.add(item); }
 public T get(int index) { return array.get(index); }
}

如何創建真正的泛型數組呢?我們不能直接創建,但可以定義泛型數組的引用。比如:

?
1
2
3
public class ArrayOfGenericReference {
 static Generic<Integer>[] gia;
}

gia 是一個指向泛型數組的引用,這段代碼可以通過編譯。但是,我們并不能創建這個確切類型的數組,也就是不能使用 new Generic<Integer>[]  具體參見下面的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ArrayOfGeneric {
 static final int SIZE = 100;
 static Generic<Integer>[] gia;
 @SuppressWarnings("unchecked")
 public static void main(String[] args) {
 // Compiles; produces ClassCastException:
 //! gia = (Generic<Integer>[])new Object[SIZE];
 // Runtime type is the raw (erased) type:
 gia = (Generic<Integer>[])new Generic[SIZE];
 System.out.println(gia.getClass().getSimpleName());
 gia[0] = new Generic<Integer>();
 //! gia[1] = new Object(); // Compile-time error
 // Discovers type mismatch at compile time:
 //! gia[2] = new Generic<Double>();
 Generic<Integer> g = gia[0];
 }
} /*輸出:
Generic[]
*///:~

數組能追蹤元素的實際類型,這個類型是在數組創建的時候建立的。上面被注釋掉的一行代碼: gia = (Generic<Integer>[])new Object[SIZE],數組在創建的時候是一個 Object 數組,如果轉型便會報錯。成功創建泛型數組的唯一方式是創建一個類型擦除的數組,然后轉型,如代碼: gia = (Generic<Integer>[])new Generic[SIZE],gia 的 Class 對象輸出的名字是 Generic[]。

我個人的理解是:由于類型擦除,所以 Generic<Integer> 相當于初始類型 Generic,那么 gia = (Generic<Integer>[])new Generic[SIZE] 中的轉型其實還是轉型為 Generic[],看上去像沒轉,但是多了編譯器對參數的檢查和自動轉型,向數組插入 new Object()new Generic<Double>()均會報錯,而 gia[0] 取出給 Generic<Integer> 也不需要我們手動轉型。

使用 T[] array

上面的例子中,元素的類型是泛型類。下面看一個元素本身類型是泛型參數的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GenericArray<T> {
 private T[] array;
 @SuppressWarnings("unchecked")
 public GenericArray(int sz) {
 array = (T[])new Object[sz]; // 創建泛型數組
 }
 public void put(int index, T item) {
 array[index] = item;
 }
 public T get(int index) { return array[index]; }
 // Method that exposes the underlying representation:
 public T[] rep() { return array; } //返回數組 會報錯
 public static void main(String[] args) {
 GenericArray<Integer> gai =
 new GenericArray<Integer>(10);
 // This causes a ClassCastException:
 //! Integer[] ia = gai.rep();
 // This is OK:
 Object[] oa = gai.rep();
 }
}

在上面的代碼中,泛型數組的創建是創建一個 Object 數組,然后轉型為 T[]。但數組實際的類型還是 Object[]。在調用 rep()方法的時候,就報 ClassCastException 異常了,因為 Object[] 無法轉型為 Integer[]。

那創建泛型數組的代碼 array = (T[])new Object[sz] 為什么不會報錯呢?我的理解和前面介紹的類似,由于類型擦除,相當于轉型為 Object[],看上去就是沒轉,但是多了編譯器的參數檢查和自動轉型。而如果把泛型參數改成 <T extends Integer> ,那么因為類型是擦除到第一個邊界,所以 array = (T[])new Object[sz] 中相當于轉型為 Integer[],這應該會報錯。下面是實驗的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GenericArray<T extends Integer> {
 private T[] array;
 @SuppressWarnings("unchecked")
 public GenericArray(int sz) {
 array = (T[])new Object[sz]; // 創建泛型數組
 }
 public void put(int index, T item) {
 array[index] = item;
 }
 public T get(int index) { return array[index]; }
 // Method that exposes the underlying representation:
 public T[] rep() { return array; } //返回數組 會報錯
 public static void main(String[] args) {
 GenericArray<Integer> gai =
 new GenericArray<Integer>(10);
 // This causes a ClassCastException:
 //! Integer[] ia = gai.rep();
 // This is OK:
 Object[] oa = gai.rep();
 }
}

相比于原始的版本,上面的代碼只修改了第一行,把  <T> 改成了 <T extends Integer>   那么不用調用 rep(),在創建泛型數組的時候就會報錯。下面是運行結果:

?
1
2
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at GenericArray.<init>(GenericArray.java:15)

使用 Object[] array

由于擦除,運行期的數組類型只能是 Object[],如果我們立即把它轉型為 T[],那么在編譯期就失去了數組的實際類型,編譯器也許無法發現潛在的錯誤。因此,更好的辦法是在內部最好使用 Object[] 數組,在取出元素的時候再轉型??聪旅娴睦樱?/p>

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class GenericArray2<T> {
 private Object[] array;
 public GenericArray2(int sz) {
 array = new Object[sz];
 }
 public void put(int index, T item) {
 array[index] = item;
 }
 @SuppressWarnings("unchecked")
 public T get(int index) { return (T)array[index]; }
 @SuppressWarnings("unchecked")
 public T[] rep() {
 return (T[])array; // Warning: unchecked cast
 }
 public static void main(String[] args) {
 GenericArray2<Integer> gai =
 new GenericArray2<Integer>(10);
 for(int i = 0; i < 10; i ++)
 gai.put(i, i);
 for(int i = 0; i < 10; i ++)
 System.out.print(gai.get(i) + " ");
 System.out.println();
 try {
 Integer[] ia = gai.rep();
 } catch(Exception e) { System.out.println(e); }
 }
} /* Output: (Sample)
0 1 2 3 4 5 6 7 8 9
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
*///:~

現在內部數組的呈現不是 T[] 而是 Object[],當 get() 被調用的時候數組的元素被轉型為 T,這正是元素的實際類型。不過調用 rep() 還是會報錯, 因為數組的實際類型依然是Object[],終究不能轉換為其它類型。使用 Object[] 代替 T[] 的好處是讓我們不會忘記數組運行期的實際類型,以至于不小心引入錯誤。

使用類型標識

其實使用 Class 對象作為類型標識是更好的設計:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class GenericArrayWithTypeToken<T> {
 private T[] array;
 @SuppressWarnings("unchecked")
 public GenericArrayWithTypeToken(Class<T> type, int sz) {
 array = (T[])Array.newInstance(type, sz);
 }
 public void put(int index, T item) {
 array[index] = item;
 }
 public T get(int index) { return array[index]; }
 // Expose the underlying representation:
 public T[] rep() { return array; }
 public static void main(String[] args) {
 GenericArrayWithTypeToken<Integer> gai =
 new GenericArrayWithTypeToken<Integer>(
 Integer.class, 10);
 // This now works:
 Integer[] ia = gai.rep();
 }
}

在構造器中傳入了 Class<T> 對象,通過 Array.newInstance(type, sz) 創建一個數組,這個方法會用參數中的 Class 對象作為數組元素的組件類型。這樣創建出的數組的元素類型便不再是 Object,而是 T。這個方法返回 Object 對象,需要把它轉型為數組。不過其他操作都不需要轉型了,包括 rep() 方法,因為數組的實際類型與 T[] 是一致的。這是比較推薦的創建泛型數組的方法。

總結

數組與泛型的關系還是有點復雜的,Java 中不允許直接創建泛型數組。本文分析了其中原因并且總結了一些創建泛型數組的方式。其中有部分個人的理解,如果錯誤希望大家指正。下一篇會總結通配符的使用

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!

原文鏈接:https://segmentfault.com/a/1190000005179147

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 欧美精品一区二区三区在线播放 | 久久久久国产精品免费免费搜索 | 亚洲激情一区二区三区 | 日韩电影免费观看 | 在线视频一区二区三区 | 夜色影院在线观看 | 午夜看片在线观看 | 精品日韩视频 | 在线视频一区二区 | 中文字幕在线精品 | 色综合天天综合网国产成人综合天 | 欧美日韩国产中文 | 亚洲香蕉视频 | 自拍偷拍一区 | 日韩中文字幕一区二区 | 欧美日韩国产一区二区三区 | 成人在线播放 | 日本三级电影网站 | 亚洲 中文 欧美 日韩 在线观看 | 国产综合中文字幕 | 永久免费av片在线观看全网站 | 国产在线高清 | 欧美成人综合在线 | 一本久久a久久精品亚洲 | 成人av高清在线观看 | 99国产精品久久久久久久成人热 | 五月婷婷导航 | 91人人| 久久久一区二区 | 91精品国产一区二区三区香蕉 | 国产精品午夜电影 | 亚洲成人av免费观看 | 午夜男人视频 | 亚洲一区二区中文字幕 | 后人极品翘臀美女在线播放 | 91精品一区二区 | 国产亚洲网站 | 日韩av免费在线 | 羞羞羞羞 | 天天干天天干天天干天天射 | 欧美一区二区精品 |