-
2022-06-21 17:03:02
首先理解两个概念。
1. 共变数组(covariant array)
在 Java 中, array具有共变性。
共变性的意思是说,一个 类型为 T[ ] 的数组可以包含,类型为 T 的元素或者 subtype 类型为 T 的元素。
所以我们可以这样做:
Number[] numbers = newNumber[3]; numbers[0] = newInteger(10); numbers[1] = newDouble(3.14); numbers[2] = newByte(0);
不仅如此,如果 S 是 T 的 subtype, 一个类型为 S[ ] 的数组也是类型 T [ ]数组的 subtype。例如 Integer 是 Number 的 Subtype, 我们可以这么做:
Integer[] myInts = {1,2,3,4}; Number[] myNumber = myInts;
如果这样做呢? 不通过类型对象直接赋值。
myNumber[0] = 3.14;
上面的代码直接给 类型为T[ ] 的数组赋值, 在编译期间是没有问题的,
但如果运行这段代码,将引发一个错误警告 ArrayStoreException。
这是因为在运行期间,Java 知道这个数组被实例化为整形数组。
2. 类型擦除(type erasure)
在 Java 泛型中,泛型类型是一种类型信息,且在编译之后被编译器丢弃。
所以泛型的类型信息,在运行期间是不存在的。
这个过程叫做「类型擦除」。
//例如: //Java 是一个面对对象语言, 所有的元素在 Java 中都关联着类和对象。 //Java 的 Object 类是所有类的父类。 //所以 𝚂𝚝𝚛𝚒𝚗𝚐[ ] 是 𝙾𝚋𝚓𝚎𝚌𝚝[] 的subtype 但 𝚂𝚝𝚊𝚌𝚔<𝚂𝚝𝚛𝚒𝚗𝚐> 不是 𝚂𝚝𝚊𝚌𝚔<𝙾𝚋𝚓𝚎𝚌𝚝> 的 subtype
另外,泛型没有共变性。
3. 为什么禁止泛型数组?
继续上一个例子:
//因为类型擦除,泛型类型在运行期间,Stack 的 String 类型会被擦除成 Stack。 //所有的 Stack 泛型类型分享同一个 Stack.class //但数组中,不同类型的数组都有自己的 class。 //结合数组的共变性,即便像 1.中的 不通过类型对象直接赋值。 //我们能在编译期间能暂时骗过编译器,但在运行期间,Java 知道我们在做什么, //也就是数组的类型在运行期间不能被擦除,这与泛型的类型擦除相矛盾,所以 Java中禁止了泛型数组。
更多相关内容 -
c#实现对泛型数组排序
2020-12-26 20:25:44c#实现对泛型数组排序 -
java泛型数组
2017-03-17 15:42:48泛型数组的创建 -
C# 泛型数组学习小结
2021-01-20 06:50:12C# 泛型和数组在 C# 2.0 中,下限为零的一维数组自动实现 IList。这使您可以创建能够使用相同代码循环访问数组和其他集合类型的泛型方法。此技术主要对读取集合中的数据很有用。IList<T> 接口不能用于在数组中添加或... -
java不支持创建泛型数组(1)
2019-03-17 02:08:45NULL 博文链接:https://xnn.iteye.com/blog/572501 -
泛型数组
2021-04-11 13:54:39定义泛型数组 在写程序时,大家可能会遇到类似String[] list = new String[8];的需求,这里可以定义String数组,当然我们也可以定义泛型数组,泛型数组的定义方法为 T[],与String[]是一致的,下面看看用法: ...定义泛型数组
在写程序时,大家可能会遇到类似String[] list = new String[8];的需求,这里可以定义String数组,当然我们也可以定义泛型数组,泛型数组的定义方法为 T[],与String[]是一致的,下面看看用法:函数fun1(),定义返回值为T[],参数为接收的T类型的可变长参数。如果有同学对T...arg的用法不了解,可以去找下JAVA 可变长参数方面的知识。
由于可变长参数在输入后,会保存在arg这个数组中,所以,我们直接把数组返回即可。 -
泛型数组初始化
2022-06-09 18:13:09实际的运行时对象数组是Object[]...结论不能(直接)创建泛型数组泛型数组实际的运行时对象数组只能是原始类型( T[]为Object[],Pair[]为Pair[] ),而实际的运行时数组对象可能是T类型( 虽然运行时会擦除成原始类型 )...- 对整个数组强制转型的例子(错误方法);
package test; public class GenericParadigm<T> { private T[] array; public GenericParadigm(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]; } public T[] rep() { return array; } //应该在运行时出口做文章 public static void main (String[] args){ GenericParadigm gai = new GenericParadigm(10); // Integer[] ia = gai.rep(); //ClassCastException Object[] oa = gai.rep(); //只能返回对象数组类型为Object[] } }
实际的运行时对象数组是Object[],而实际的运行时数组对象可能是T类型。
因此,应该在运行时,数组对象的出口做转型输出,入口方法在编译期已实现类型安全,所以出口方法可以放心强制类型转换,保证成功.
public class GenericArray2 { private Object[] array; //维护Object[]类型数组 public GenericArray2(int sz) { array = new Object[sz]; } public void put(int index, T item) { array[index] = item; } public T get(int index) { return (T)array[index]; }//数组对象出口强转 public T[] rep() { return (T[])array; } //运行时无论怎样都是Object[]类型 public static void main (String[] args){ GenericArray gai = new GenericArray(10); // Integer[] ia = gai.rep(); //依旧ClassCastException Object[] oa = gai.rep(); //只能返回对象数组类型为Object[] gai.put(0,11); System.out.println(gai.get(0)); // 11 ,出口成功转型 } }
- 通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无
ClassCastException
.
public class GenericArrayWithTypeToken { private T[] array; public GenericArrayWithTypeToken(Class type, int sz) { array = (T[]) Array.newInstance(type, sz);//通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无ClassCastException } public void put(int index, T item){ array[index] = item; } public T get(int index) { return array[index]; } public T[] rep() { return array; } //能成功返回了~ public static void main(String[] args) { GenericArrayWithTypeToken gawtt = new GenericArrayWithTypeToken<>(Integer.class, 10); Integer[] ia = gawtt.rep(); //能成功返回了! } }
模板
public class ArrayQueue<T> { private int front=0;//头部指针,空 private int rear=0;//尾部指针,有值 private int maxSize=10;//容量,默认给10 private T[] array;//数组,存储内容 public ArrayQueue(Class<T> clazz,int maxSize) { this.maxSize = maxSize; array = (T[]) Array.newInstance(clazz, maxSize); } }
结论
不能(直接)创建泛型数组
泛型数组实际的运行时对象数组只能是原始类型( T[]为Object[],Pair[]为Pair[] ),而实际的运行时数组对象可能是T类型( 虽然运行时会擦除成原始类型 )
-
Java 为什么不支持泛型数组?
2022-01-25 23:42:48使用泛型的一个编译失败,由此可知,Java 不支持泛型数组。 List<Integer>[] list = new LinkedList<Integer>[10];// 无法通过编译 List[] list = new LinkedList[10]; 原因 Java 泛型通过类型...问题
首先对比一下以下两段代码,都是声明两个数组,其中一个使用泛型,一个不使用泛型。使用泛型的一个编译失败,由此可知,Java 不支持泛型数组。
List<Integer>[] list = new LinkedList<Integer>[10];// 无法通过编译
List[] list = new LinkedList[10];
原因
Java 泛型通过类型擦除实现,编译时类型参数就会被擦掉。例如:声明一个 List<String>,一个 List<Integer>,编译后,都变为 List,并且在 JVM 中是同一个 class 对象 List.class。
List<String> stringList = new LinkedList<String>(); List<Integer> integerList = new LinkedList<Integer>(); // 输出true System.out.println(stringList.getClass()==integerList.getClass());
假设 Java 允许使用泛型数组,我们看看有什么问题。
List<String>[] list = new LinkedList<String>[10];
经过类型擦除后。
List[] list = new LinkedList[10];
接下来我们就可以往数组中放东西了。
list[1] = new LinkedList<String>(); list[0] = new LinkedList<Integer>(); // 编译通过
这里就出现问题了,声明的是 LinkedList<String> 类型的数组,但是居然成功放入了一个 LinkedList<Integer>(),这与 Java 协变数组类型有关,出现了类型安全问题,所以 Java 中不支持泛型数组。
创建泛型数组的唯一方式,是先创建一个擦除类型的数组,然后使用强制类型转型,这种类型转换将产生一个关于未检验的类型转换的编译警告。
List<String>[] list = (LinkedList<String>[]) new LinkedList[10]; list[0] = new LinkedList<String>(); list[1] = new LinkedList<Integer>();// 报错
-
什么是泛型数组?已经有了数组为什么还要用到泛型数组?
2022-03-23 20:34:47泛型数组使用的好处: 在我们编程的时候,当我们用到数组的时候,我们总是,提前就确定好了数组的大小,并且数组的大小是不可变得,但是有些时候我们并不能确定数组的大小,所以为了避免在编译是就确定数组的大小,... -
解决在[在泛型方法中返回泛型数组]
2022-04-26 11:13:21解决在[在泛型方法中返回泛型数组] java泛型的本质是:Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化... -
如何声明泛型数组
2021-03-22 08:20:05结论:使用反射可以声明泛型数组,用到的类是java.lang.reflect包下的Array类。 先来看看泛型数组错误出现的代码 class Human<T,V> { class Node{ T t; V v; } private Node[] nodes; public Human() {... -
Java中泛型数组创建总结
2021-02-26 18:21:15在java中,可以声明一个泛型数组,不能通过直接通过T[] tarr=new T[10]的方式来创建数组,最简单的方式便是通过Array.newInstance(Classtype,int size)的方式来创建数组例如下面的程序。public class ArrayMaker {... -
Java 泛型数组
2021-02-28 16:00:25Java 不支持泛型数组。也就是说,List[]ls=newArrayList[10];是不支持的,而List[]ls=newArrayList[10]却可以。是我一直不清楚为什么不能够声明泛型的数组,指定类型可以让编译的时候不会出现类型安全的提示。直到... -
5、ts中的数组、泛型数组
2021-12-01 21:47:23ts中的数组、泛型数组 -
【Java泛型】泛型数组
2022-01-22 14:16:50可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象,可以通过java.lang.reflect.Array的newInstance(Class<T>, int )创建T[]数组 2.示例 import java.lang.reflect.Array; public class Fruit&... -
java中创建泛型数组的方法
2021-03-13 01:37:09我们对于数组的创建,需要遵照一定的规则,就拿泛型数组来说,其实是不适合在java中建立的。不过也不是没有其他的方法,我们依旧可以用一些特殊的方法,达到数组的创建。本篇就以泛型数组为例,探讨其创建的方法。... -
泛型数组需要怎么建立? --《JAVA编程思想》 54
2021-09-19 16:21:27今天和大家一起探讨如何创建一个泛型数组? 可能会有人说,这还不简单,直接 T[] array = new T[size],不就可以了嘛? 很可惜,编译器会提示泛型无法直接被实例化。 那我们换个思路,先创建一个 Object 数组,再将... -
泛型数组初始化-java
2022-04-21 04:39:02public class ArrayQueue<T> { private int front=0;//头部指针,空 private int rear=0;...//数组,存储内容 public ArrayQueue(Class<T> clazz,int maxSize) { this.maxSize = ma. -
Java中不能创建泛型数组
2022-04-08 08:28:48listStr.add("...") 此时如果把listStr赋值到objects的第一个里,原则上是没有任何问题的 因为Object是所有类的父类 但是这个地方应该是Integer泛型的ArrayList,如果这样允许存在, 要么运行时出现类转化异常 ... -
Java不支持泛型数组
2020-11-04 10:23:02不能创建泛型数组的原因:Java的泛型是伪泛型(类型擦除),这些伪泛型在编译的时候是不能具化的。换句话说就是,虽然我们给自己定义的泛型制定了比较丰富的含义,但是在编译的时候它包含的描述信息是缺少、不足的, -
泛型数组List和数组转换常见方法归纳 + 流方法解析
2020-04-16 14:40:02本文为归纳总结,不会具体说明用法或案例,但会附上相关链接 ...文章目录引用类型数组转换泛型数组 to 引用类型数组引用类型数组 to 泛型数组基本类型数组转换泛型数组 to 基本类型数组基本类型数组 to... -
Java如何:从具有泛型的类创建泛型数组?
2021-03-09 09:24:14解决方法: Java对泛型的处理非常粗糙,但是如果您准备进行细微调整,则可以完成接近所需的操作.请参见: public class FirstClass { Class type; public static FirstClass create(Class type) { return new ... -
Java编程经验——怎样创建泛型数组
2021-02-12 09:45:47有两种办法解决上面的错误,第一种是通过创建一个Object类型的数组,然后显示转换为E[]类型。见下面的代码:import java.util.EmptyStackException;public class TestGenericArray { private E[]elements; private ... -
Java封装数组之改进为泛型数组操作详解
2021-03-13 22:44:21本文实例讲述了Java封装数组之改进为泛型数组操作。分享给大家供大家参考,具体如下:前言:通过上一节我们对我们需要封装的数组,进行了基本的增删改查的封装,但只局限于int类型的操作,为了能提供多种类型数组的... -
Java中泛型数组的使用
2020-09-25 10:34:44Java中泛型数组的使用 构想初衷:众所周知,Java在当前现阶段的各个版本当中,提供的Array数组均有不可变性。无论是直接创建数组还是间接创建数组,数组的长度均不可变。这就导致在使用数组时,无法实现数组的改变... -
泛型数组怎么初始化
2021-04-01 17:24:54一 泛型数组初始化问题 这个用法是在自己写动态数组的时候遇到的问题,需要在构造器中创建初始化的数组,但是因为泛型不能直接创建,所以需要先创建一个Object对象,再强制转换类型,这个做法其实不太好,这里又涉及... -
Java自定义泛型数组
2019-02-13 23:31:051、定义泛型数组相关概念 (1)泛型数组让我们可以存放任何数据类型 (2)存放的类型不可以是基本数据类型,只能是类对象 boolean、byte、char、short、int、long、float、double (3)每个基本数据类型都...