网站流量增加,南宁制作营销型网站,做电影网站技术,房屋设计图怎么制作无法创建t的通用数组在这篇文章中#xff0c;我们将介绍一篇全面的文章#xff0c;其中介绍了创建通用数组的问题。 Java编程语言于2004年9月在Java 5.0“ Tiger”发行版中添加了泛型。 泛型或类型参数化系统在提供类型安全性的同时扩展了Java现有的类型系统。 1.简介 Java具… 无法创建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 TestArray1 TestArray1.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 constructor varargs是作为基本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 getIndex getIndex方法的源代码在实际计算内部线性数组中的一维索引之前先验证索引的维度。 索引验证 有两种验证索引的方法。 一种是验证多维索引另一种是验证单个索引。 验证一维索引的源代码为 void isValidIndex(final int idx){ if(idx this.size) throw new RuntimeException(Index Overflow Error!); }//end isValidIndex isValidIndex仅检查索引在数学上是否在零到内部数组整体大小的范围内。 如果索引不在该范围内则会引发运行时未经检查的异常。 验证多维索引的源代码为 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 isValidDims isValidDims仅遍历每个维度参数并检查索引的等级是否与数组的等级参数相同。 如果数组的等级和索引不相等则会抛出运行时未经检查的异常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 copy System.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 x0;x 0) { Integer temp list.get(x); list.set( list.get(x1), x); list.set( temp, (x1)); 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 x0;xmultiplyTable.getDim(0);x){ for(int y0;ymultiplyTable.getDim(1);y){ multiplyTable.set(x*y, x,y); }//end for }//end for //check 1*n n for(int x0;xmultiplyTable.getDim(0);x){ if(multiplyTable.get(1,x) ! x) throw new RuntimeException(Identity property doesnt hold!”); if(multiplyTable.get(x,1) ! x) throw new RuntimeException(Identity property doesnt hold!”); }//end for //check m*n n*m for(int x0;xmultiplyTable.getDim(0);x){ for(int y0;ymultiplyTable.getDim(1);y){ if(multiplyTable.get(x,y) ! multiplyTable.get(y,x) ) throw new RuntimeException(Commutative property doesnt 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] AhoAlfred V.LamMonica S.SethiRavi和UllmanJeffrey D.编译器原理技术和工具第二版。 皮尔逊教育公司Pearson EducationInc.纽约纽约2007年第381至382页。 [Goet 2019] GoetzBrian。 “ 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的通用数组