无法创建t的通用数组_创建通用数组的问题
無法創建t的通用數組
在這篇文章中,我們將介紹一篇全面的文章,其中介紹了創建通用數組的問題。 Java編程語言于2004年9月在Java 5.0“ Tiger”發行版中添加了泛型。 泛型或類型參數化系統在提供類型安全性的同時擴展了Java現有的類型系統。
1.簡介
Java具有Collections Framework,它提供了用于Java軟件開發的通用數據結構庫。 集合框架缺少一種數據結構-數組。 但是,Java Collections Framework具有類型化參數化ArrayList.java和Vector.java數據結構。 兩種數據結構都使用一維動態數組,該數組使用java.lang.Object的基礎數組。
Java提供了一個內置數組,該內置數組是自1995年以來的Java 1.0以來語言規范中所包含的對象。作為對象,內置數組在Java代碼中聲明并實例化為特定類型。 內置數組是對象的容器,對象的數量和長度是固定的,可能是多個維度。
但是,使用泛型的編譯時類型安全性尚未完全實現。 特別是內置數組對象。
2.通用數組
問題是當泛型與Java中的內置數組實體一起使用時。 考慮下面的Java類TestArray1.java,它在單個泛型類型參數E周圍聲明了兩個泛型數組。Java類源代碼為:
class TestArray1 {public E[] array = new E[10]; }//end class TestArray1TestArray1.java的源代碼僅是聲明性的,不使用數組。 編寫了通用數組的兩個用例:一個用于通用數組作為類屬性,另一個用于在類的靜態(即非實例)方法中使用通用數組。
2.1編譯時的一般錯誤
編譯時,編譯器報告以下錯誤:
Error: TestArray1.java. Line 3 At 22: generic array creation public E[] array = new E[10]; ^報告了一種錯誤:通用數組創建。 此錯誤直接對應于通用數組的用例。
協方差
在Java中,數組是協變的,或對特定類型使用通用的類型專用化,例如對集合的集合。 但是,通用類型參數不是協變的。 Goetz解釋說:“ Collections類使用一個丑陋的技巧來解決此問題……” [Goet 2019]
因此,要將內置數組與Java泛型或泛型類型參數E一起使用,該數組必須為java.lang.Object類型,這是Java中的超大型類型。 一切都是一個java.lang.Object,這是丑陋的把戲。
對象數組
然而,使用對象數組的缺點是泛型必須將數據結構或變量綁定到特定類型。 對象類型的數據結構可以混合和匹配任何類型,并且需要類型轉換才能轉換為原始類型。 在這種情況下,Java中的泛型沒有用處-這是核心問題。
問題的解決方案或答案很簡單-一個通用的Java數組類。 這樣的類不在Java集合框架中,因此可以創建它。
3. Java數組類
Java Array類類似于Java集合框架中的其他數據結構,它是一個數據結構。 最初編寫的實現是為了簡單起見,并且不實現任何特定的接口或擴展任何超類。 目標是獲得功能和有用的數組作為要構建的Array.java類。 通用類型參數Array.java類的框架為:
class Array {Array(final int... dim);void init(final E elem); void init(final E[] elem);E get(final int...idx);void add(final E elem, final int... idx); }本質上,您可以構造任意級別的數組,然后構造任意大小的維度
然后,該數組具有方法init()來將數組初始化為默認值或前哨初始值。 最后,數組具有兩種主要方法,一種是在數組中的特定位置添加一個元素,另一個添加一個元素。 實例化或創建,初始化整個數組以及訪問元素的基本功能。
3.1數組類屬性
Java數組類具有幾個屬性,這些屬性定義Array.java類的實例。 通用類型參數Array.java類的屬性為:
class Array {int size; int dim[]; int rank; Object data[]; E elem; }Array.java類屬性是作為對象的內置數組的數據,該數組的邊界,例如大小,等級,尺寸。 最后,還有一個元素,即初始化元素。
3.2使用Varargs的等級和維度
Java編程語言在2004年9月發行的Java 5.0“ Tiger”中添加了變量號或參數或自變量,命名為Java變量自變量,或更簡單地說是varargs。此特殊功能允許構造函數或方法采用不同數量的參數,因此泛化參數,而不必僅僅為參數數量而復制構造函數或方法。
Array類的一般化使用此特定的Java功能:varargs,或用于創建和訪問Array.java類中的元素的變量參數。 這允許任何等級(維數),也允許任何非負整數的任何數字維。
Varargs還允許等級為一般等級,因此Array.java類的等級(至少在理論上……)沒有上限。 因此,可變參數允許在定義和使用通用Array.java類時進行整體概括。
使用Varargs的構造函數
Array.java構造函數的源代碼說明了如何使用varargs作為維,以使用Array.java類創建通用數組對象。 等級和維度是通用的,因此任何維度范圍的數組都可以排名。 Array.java構造函數的源代碼為:
Array(final int... dims) { this.rank = dims.length; this.dim = new int[rank]; int size = 1; //compute size of 1-dim internal array for (int x = 0; x < dims.length; x++) { size = size * dims[x]; dim[x] = dims[x]; }//end for //create internal "flat" array this.data = new Object[size]; this.size = size; }//end constructorvarargs是作為基本int傳遞的可變參數,它們是變量dims中的整數數組。 根據暗淡程度,可以計算和創建數組邊界的尺寸以及整個內部“平面”數組。 如果沒有可變參數,則需要針對每個維度的不同維度的構造函數。 由于有限數量的構造函數用于等級,所以Array.java通用數組類將受到限制,而對于varargs而言則不那么普遍。
帶Varargs的訪問器
通過get和set方法訪問通用數組中的元素。 這些是訪問或訪問方法。 與屬性getter和setter方法不同,對于通用數組類,維度索引指定元素。
使用varargs,可以概括訪問任何等級或維度的訪問方法。 對照通用數組的邊界和等級檢查維度索引以進行訪問。
讀取訪問者獲取
getter方法是讀取訪問器,它從數組讀取或復制一個值。 Array.java的get訪問器方法的源代碼是:
E get(final int... idx) { return (E) this.data[this.getIndex(idx)]; }//end get寫訪問器集
setter方法是寫訪問器,它將值寫入或復制到數組中。 Array.java set訪問器方法的源代碼是:
void set(final E elem, final int... idx) { this.data[this.getIndex(idx)] = elem; }//end set為簡單起見,輔助方法getIndex()進行了計算單個維度索引并檢查數組索引邊界的實際“繁重工作”。
輔助方法
在通用Array.java類中,三個輔助方法或輔助方法進行了實際處理。 一種方法,getIndex()從多個索引維度計算單個索引,其他兩種方法isValidDim()和isValidIndex()驗證所計算的索引或給定的索引沒有超出數組的邊界。 輔助方法的接口源代碼為:
class Array {int getIndex(final int... idx);boolean isValidDim(final int... idx); boolean isValidIndex(final int idx); }//end class Array繁重的工作獲得元素索引
getIndex()方法是Array.java類的核心功能。 getIndex()方法計算元素的內部一維線性或“平面”數組中的索引。 從編譯器理論(這暗示了該理論,但更深入的解釋超出了解釋的范圍),數組可以通過行主索引或列主索引來建立索引。 [Aho 2007]
對于Array.java類,它是無關緊要的,只要函數對于數組實例的維邊界的給定索引是一致的即可。 getIndex()方法的源代碼是:
int getIndex(final int... idx){ isValidDims(idx); int index = 0; for(int x = 0; x < idx.length; x++) { int i = idx[x]; for(int y = x + 1; y < idx.length; y++) { i = i * dim[y]; }//end for index = index + i; }//end for return index; }//end getIndexgetIndex()方法的源代碼在實際計算內部線性數組中的一維索引之前,先驗證索引的維度。
索引驗證
有兩種驗證索引的方法。 一種是驗證多維索引,另一種是驗證單個索引。 驗證一維索引的源代碼為:
void isValidIndex(final int idx){ if(idx = this.size) throw new RuntimeException("Index Overflow Error!"); }//end isValidIndexisValidIndex()僅檢查索引在數學上是否在零到內部數組整體大小的范圍內。 如果索引不在該范圍內,則會引發運行時未經檢查的異常。 驗證多維索引的源代碼為:
void isValidDims(final int... idx) { if(idx.length != this.dim.length) throw new RuntimeException("Rank Error"); for(int x = 0; x = dim[x]) throw new RuntimeException(“Index Overflow Error"); if(idx[x] < 0) throw new RuntimeException(“Index Underflow Error”); }//end for }//end isValidDimsisValidDims()僅遍歷每個維度參數,并檢查索引的等級是否與數組的等級參數相同。 如果數組的等級和索引不相等,則會拋出運行時未經檢查的異常RuntimeException。
3.3其他非Varargs方法
其他方法是非可變參數,它們不使用任何參數作為getter訪問器方法,也可以采用單個參數。 這兩種方法是:
查詢數組
查詢數組參數可以使用getter訪問方法或使用參數來訪問數組的參數。 該數組用于查詢等級,整體大小,上部尺寸以及等級內特定索引處的尺寸。 用于查詢Array.java類的數組方法的接口是:
class Array {int getDim(final int dim);int[] getDims();int getRank();int size(); }//end class Array獨特的數組類功能
獨特的數組類功能是一個構造函數和兩個提供獨特功能的方法。 這兩種方法是訪問并轉換為Array類實例的線性數組。 另一個功能是一個構造函數,該構造函數允許復制或復制Array類的實例。 Array.java類的功能是:
class Array {Array(final Array array);E getAt(final int idx);Object[] toArray(); }存取器為線性陣列
getAt()方法允許訪問數組元素,就像Array類實例是一維的“扁平”線性數組一樣。 檢查整數索引的有效性,并使用內部一維數組在有效位置返回元素。 作為線性數組訪問的源代碼為:
E getAt(final int index) { this.isValidIndex(index); return (E) this.data[index]; }//end getAt轉換為線性對象數組
toArray()方法轉換Array類實例,或者訪問內部的一維數組并將其作為Object數組返回。 toArray()方法返回內部線性數組的淺表副本,而不是深表副本。 用于訪問線性Object數組的getter訪問器源代碼為:
Object[] toArray() { return this.data; }//end toArray復制構造函數
復制構造函數允許復制Array類實例,但將其復制為現有Array類實例的“深層”副本。 復制的數組和副本具有相同的類型參數,尺寸,等級和元素。 復制構造函數的源代碼為:
Array(final Array orig) { this.rank = orig.rank; this.dim = orig.dim; this.size = orig.size; this.elem = (E) orig.elem; this.data = new Object[this.size]; System.arraycopy(orig.data, 0, this.data, 0, this.size); }//end constructor copySystem.arraycopy()復制原始文件,并為深度復制創建一個新的Object數組。 各種Array類實例參數被復制到深層副本中。
4.使用通用數組類
使用Java通用數組Array.java在源代碼中通過兩個用法示例進行了說明:
這兩個示例都通過演示來說明如何使用通用數組類方法圍繞數組創建,初始化,訪問,查詢和實現功能,但不使用內置Java數組。 源代碼說明了源代碼片段的輸出。
4.1氣泡排序
冒泡排序是一種基本的簡單排序算法,但是非常適合說明Array.java通用數組類的用法。 冒泡排序是通過以下通用Java數組實現的:
Array list = new Array(9).init(new Integer[]{3,5,7,4,8,0,2,1,6}); System.out.println(Arrays.toString(list.toArray())); boolean swapFlag = true; while(swapFlag) { swapFlag = false; for(int x=0;x 0) { Integer temp = list.get(x); list.set( list.get(x+1), x); list.set( temp, (x+1)); swapFlag = true; }//end if }//end for }//end while System.out.println(Arrays.toString(list.toArray()));運行時,使用通用Java數組進行冒泡排序的輸出為:
[3, 5, 7, 4, 8, 0, 2, 1, 6] [0, 1, 2, 3, 4, 5, 6, 7, 8]4.2乘法表
Java通用數組的一個基本示例性應用程序是創建一個簡單的整數表(從1到10)。這需要二維整數數組。 創建乘法表后,將驗證恒等式和可交換性的數學屬性。 通用Java數組的這種用法的源代碼為:
Array multiplyTable = new Array(10,10).init(0); for(int x=0;x<multiplyTable.getDim(0);x++){ for(int y=0;y<multiplyTable.getDim(1);y++){ multiplyTable.set(x*y, x,y); }//end for }//end for //check 1*n = n for(int x=0;x<multiplyTable.getDim(0);x++){ if(multiplyTable.get(1,x) != x) throw new RuntimeException("Identity property doesn't hold!”); if(multiplyTable.get(x,1) != x) throw new RuntimeException("Identity property doesn't hold!”); }//end for //check m*n = n*m for(int x=0;x<multiplyTable.getDim(0);x++){ for(int y=0;y<multiplyTable.getDim(1);y++){ if(multiplyTable.get(x,y) != multiplyTable.get(y,x) ) throw new RuntimeException("Commutative property doesn't hold!"); }//end for }//end for沒有輸出,因為乘法的恒等式和交換數學屬性是真實的,因此是有效的。 但這說明了二維通用數組的使用。 對于其他更高的尺寸,其他應用也是可能的。
5.結論
最初的問題證明了使用內置數組實體的參數化類型或通用數組的問題。 使用相同的代碼片段,但替換通用數組Array.java,源代碼為:
class TestArray2 { public Array array = new Array(10); }//end class TestArray2編譯時,沒有報告的錯誤。 數據結構Array.java實現了原始問題的解決方案。
Java中的類型參數化或泛型允許使用類型安全的類,但是在泛型類型參數化系統的設計中需要權衡取舍。 因此,Java中的泛型具有一些與內置Java數組實體有關的缺陷。 不幸的是,Java Collections Framework無法通過提供數組數據結構來解決該問題。
解決方案在Java語言和通用類型參數化內。 只需將通用Array類設計為用Java編寫的一流對象即可。 從表面上看,它似乎是現有Java實體(數組)的冗余副本。
這不是復制; 設計Java Array類將創建一個通用的類型安全的數據結構,該結構可以替代內置Java數組實體。 折衷方案是在沒有運算符重載的情況下,語法在數組訪問和操作方面不太明確,但與在對象實例上調用方法一致。
6.參考
- [Aho 2007] Aho,Alfred V.,Lam,Monica S.,Sethi,Ravi和Ullman,Jeffrey D.編譯器:原理,技術和工具,第二版。 皮爾遜教育公司(Pearson Education,Inc.),紐約,紐約,2007年,第381至382頁。
- [Goet 2019] Goetz,Brian。 “ Java理論與實踐:泛型陷阱”,2005年1月25日。https ://www.ibm.com/developerworks/java/library/j-jtp01255/index.html,于2019年9月28日訪問。
7.下載源代碼
下載您可以在此處下載本文的完整源代碼: 創建通用數組的問題
翻譯自: https://www.javacodegeeks.com/the-problem-with-creating-generic-arrays.html
無法創建t的通用數組
總結
以上是生活随笔為你收集整理的无法创建t的通用数组_创建通用数组的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: camel apache_Apache
- 下一篇: 余承东:华为穿戴设备登陆迪拜地标6000