激情久久久_欧美视频区_成人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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 性明星video另类hd | 欧美日韩在线视频一区 | 国产精品刺激对白麻豆99 | 欧洲精品色 | 黄色免费高清网站 | 日韩视频―中文字幕 | 亚洲一区二区三区在线看 | 国产精品18久久久久久久久 | 欧美一级黄色录相 | 国产精品久久久在线观看 | 午夜精品久久久久久中宇 | 久久视频精品 | 国产99久久久久久免费看农村 | 综合成人在线 | 精品一区二区三区在线播放 | 免费国产一级特黄久久 | 久久草草影视免费网 | 4480午夜| 精品国产一区二区三区久久久蜜 | 中文字幕在线免费看 | 在线免费日本 | 久久精品国产亚洲aa级女大片 | 国产精品久久久久一区二区 | av手机免费在线观看 | 免费视频xxxx | 哪里可以看免费的av | 亚洲精品午夜国产va久久成人 | 久久精品毛片 | 久草欧美 | 一级毛片电影网 | 成年人观看免费视频 | 99久久久精品国产一区二区 | 男人久久天堂 | 91aa.app| 中国av免费观看 | 欧美18videos性处按摩 | 成人在线观看一区 | 亚洲小视频网站 | 日日爱99 | 九色com| 激情免费视频 |