无法创建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 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访问器方法,也可以采用单个参数。 这两种方法是:

  1. 查询数组参数
  2. 独特的阵列功能

查询数组

查询数组参数可以使用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在源代码中通过两个用法示例进行了说明:

  1. 气泡排序算法
  2. 乘法表

这两个示例都通过演示来说明如何使用通用数组类方法围绕数组创建,初始化,访问,查询和实现功能,但不使用内置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的通用数组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

贪婪算法+小应用(调度问题)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “DFS应用——贪婪算法” 的idea&#xff1b; 【1】贪婪算法 1.1&#xff09;已经看到的三个贪婪算法&#xff1a; Dijkstra算、Prim算法 和 Kruskal 算法&#xff1b;&#xff08;Dijkstr…

http 安全性和幂等性_HTTP方法:幂等性和安全性

http 安全性和幂等性幂等性和安全性是HTTP方法的属性。 HTTP RFC定义了这些属性&#xff0c;并告诉我们哪些HTTP方法是安全且幂等的。 服务器应用程序应确保正确执行安全和幂等的语义&#xff0c;如客户端期望的那样。 安全的HTTP方法 如果HTTP方法不更改服务器状态&#xff0…

Huffman编码(Huffman树)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “Huffman编码&#xff08;Huffman树&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; Huffman树的构建算法属于 贪婪算法&#xff0c;…

java获取文件列表_java获取指定目录中的文件列表

最近项目中会动态生成文件html及相关资源文件(css,js,png,mp3)&#xff0c;为了防止文件名重复&#xff0c;需要获取目录中相同类型文件的最大编号&#xff0c;下面我用代码来实现获得文件列表。public static void getFiles(String path) {File file new File(path);// 如果这…

jep290涉及jdk版本_针对JDK 14提议的另外六个JEP

jep290涉及jdk版本Mark Reinhold最近的消息宣布了六个新的“建议针对JDK 14的JEP ”&#xff1a; JEP 345 &#xff0c; JEP 361 &#xff0c; JEP 363 &#xff0c; JEP 364 &#xff0c; JEP 365和JEP 367 。 假设没有异议由11月7日提出&#xff0c;这些JEPs将有针对性地JDK …

近似装箱问题(三种联机算法实现)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “近似装箱问题&#xff08;三种联机算法实现&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 近似装箱问题的三种联机算法 分别是&am…

java 随机数种子_Java--随机数和随机数种子(转)

在计算机中并没有一个真正的随机数发生器&#xff0c;但是可以做到使产生的数字重复率很低&#xff0c;这样看起来好象是真正的随机数&#xff0c;实现这一功能的程序叫伪随机数发生器。有关如何产生随机数的理论有许多&#xff0c;如果要详细地讨论&#xff0c;需要厚厚的一本…

java 堆转储快照_捕获Java堆转储的7个选项

java 堆转储快照堆转储是诊断与内存相关的问题的重要工件&#xff0c;例如内存泄漏缓慢&#xff0c;垃圾回收问题和java.lang.OutOfMemoryError。它们也是优化内存消耗的重要工件。 有很棒的工具&#xff0c;例如Eclipse MAT和Heap Hero&#xff0c;可以分析堆转储。 但是&…

java 提取url参数_Java提取URL某个参数的值

ASP&period;NET Core 中文文档 第四章 MVC(4&period;3)过滤器原文:Filters 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐 ASP.NET MVC 过滤器 可在执行管道的前后特定阶段执行代码.过滤器可以配置为全局有效.仅对控 ...jquery插件-表单提交插件-jQuery&peri…

近似装箱问题(两种脱机算法实现)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “近似装箱问题&#xff08;两种脱机算法实现&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 近似装箱问题的两种联机算法 分别是&am…

vaadin 10+_Vaadin 10+作为CUBA UI的未来

vaadin 10从一开始&#xff0c;Vaadin就成为CUBA平台用户界面的基石和重要组成部分。 凭借其创新的方法&#xff0c;它帮助CUBA将企业用户界面开发带到了一个非常有希望&#xff08;当今是默认&#xff09;的WEB领域。 Vaadin最令人兴奋的部分之一是整个开发都是同构的&#xf…

java 信息增益_对信息增益(IG,Information Gain)的理解和计算

可能理解的不对。决策树构建中节点的选择靠的就是信息增益了。信息增益是一种有效的特征选择方法&#xff0c;理解起来很简单&#xff1a;增益嘛&#xff0c;肯定是有无这个特征对分类问题的影响的大小&#xff0c;这个特征存在的话&#xff0c;会对分类系统带来多少信息量&…

使用文本编辑器和jdk_JDK 14:记录,文本块等

使用文本编辑器和jdk今天的Mark Reinhold帖子“ 建议JEP针对JDK 14&#xff1a;305、343、359、366和368 ”建议将另外五个JEP针对JDK 14 。 该组中有一些备受期待的功能&#xff0c;但建议将所有功能都“预览”或“孵化”&#xff1a; JEP 305 &#xff1a;instanceof的模式匹…

java compareable接口_Java对象比较-Comparable和Comparator接口使用

最近在学习贪心算法和动态规划的过程中&#xff0c;里面有一段自然排序的操作&#xff0c;顺便简单了解一下Java中对象比较后排序要使用的两个接口&#xff1a;Comparable和Comparator。如果是数字&#xff0c;直接比较就行&#xff0c;但是如果是对象&#xff0c;如何比较后排…

java初学者指南_Java代理初学者指南

java初学者指南尽管Java初学者很快学会了键入public static void main来运行他们的应用程序&#xff0c;但是即使是经验丰富的开发人员也常常不知道JVM对Java流程的两个附加入口点的支持&#xff1a; premain和agentmain方法。 这两种方法都允许所谓的Java代理在驻留在其自己的…

java txt html格式_java中xml(txt/html等格式)解析问题,请教java高手,请勿粘贴其他网页上的内容(能查的都看了)。...

目的&#xff1a;通过对网页内容解析&#xff0c;获得需要的内容&#xff0c;如网页的标题Title&#xff0c;主要内容&#xff0c;描述信息&#xff1b;而里面的广告、超链接、无关紧要的信息统统不要&#xff0c;从而达到对用户上网行为的分析的目的。下面是我...目的&#xf…

java泛型程序设计——定义简单泛型类+泛型方法

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java泛型程序设计 的 定义泛型类泛型方法的知识&#xff1b; 【1】一个泛型类&#xff1a; 就是具有一个或多个类型变量的类&#xff1b; 1.1&#xff09;看个荔枝&#xff1a; …

分布式 虚拟时间和虚拟同步_分布式虚拟跟踪

分布式 虚拟时间和虚拟同步跟踪提供了对系统的可见性&#xff0c;使开发人员和操作人员可以在运行时观察应用程序。 当系统不断增长并与更多微服务进行交互时&#xff0c;跟踪变得非常有价值。 在这样的环境中&#xff0c;这些痕迹非常棒&#xff0c;可以定位导致性能下降的故障…

java泛型程序设计——类型变量限定 + 泛型代码和虚拟机

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java泛型程序设计 的 类型变量限定 泛型代码和虚拟机 的知识&#xff1b; 【1】类型变量的限定 1.1&#xff09;类和方法需要对类型变量加以限定 1.1.1&#xff09;看个荔枝&a…

java中装饰器_Java设计模式12:装饰器模式

装饰器模式装饰器模式又称为包装(Wrapper)模式。装饰器模式以多客户端透明的方式扩展对象的功能&#xff0c;是继承关系的一个替代方案。装饰器模式的结构通常给对象添加功能&#xff0c;要么直接修改对象添加相应的功能&#xff0c;要么派生子类来扩展&#xff0c;抑或是使用对…