JAVA为什么不让创建泛型数组

本文探讨了Java泛型在数组应用上的限制及其原因。通过示例说明了即使使用泛型,数组也无法确保类型安全,并解释了这可能导致的ClassCastException异常。

首先,我觉得定制java标准的那些人完全可以让java创建泛型数组;只是他们权衡了一下,觉得还是禁止了的好,一下就说说我的揣测:

如果我们写如下代码是没有问题的:

List<String> a = new ArrayList<String>();
那么为嘛到了数组就不行呢:

List<String>[] arr = new ArrayList<String> [10];
我们先来看看数组变量和普通变量的区别:数组变量arr和普通变量a都在栈中,但是呢!arr[0]在堆中。所以呢?所以我们有下面一个例子:

List<String>[] arr = new ArrayList<String> [10];
Object[] orr = arr;
List<StringBuffer> buf = new ArrayList<StringBuffer> ();
orr[0] = buf;
List<String> str = arr[0];
String val = str.getValue();
可以发现,堆中的第0个元素是List<StringBuffer>了,但是arr[0]还是指向了它,如果是普通变量,这是不可能的;所以,即便是引入了泛型,也不是安全的;最后一句,由于编译器会加上string转化,造成ClassCastException;泛型本来就是为了安全,如果不能保证数组的安全,为啥还有多此一举呢?

本文主要参照:http://www.blogjava.net/deepnighttwo/articles/298426.html



Java 中,由于的类擦除机制,不能直接实例化参数化类数组,如 `Peel<Banana>[] peels = new Peel<Banana>[10];` 这种写法是不合法的 [^1]。不过,可以通过以下几种方法来初始化数组: ### 方法一:通过创建 Object 数组并进行强制类转换 可以先创建一个 `Object` 类数组,然后将其强制转换为数组。示例代码如下: ```java import java.util.Arrays; class Peel<T> {} public class GenericArrayInitialization { public static void main(String[] args) { @SuppressWarnings("unchecked") Peel<Banana>[] peels = (Peel<Banana>[]) new Object[10]; // 可以对数组元素进行赋值等操作 peels[0] = new Peel<>(); System.out.println(Arrays.toString(peels)); } } class Banana {} ``` 这种方法需要使用 `@SuppressWarnings("unchecked")` 注解来抑制编译器的警告,因为强制类转换可能会在运行时导致 `ClassCastException`。 ### 方法二:使用集合类 可以使用 Java 的集合类(如 `ArrayList`)来替代数组,集合类在处理时更加安全和灵活。示例代码如下: ```java import java.util.ArrayList; import java.util.List; class Peel<T> {} class Banana {} public class GenericCollection { public static void main(String[] args) { List<Peel<Banana>> peels = new ArrayList<>(); for (int i = 0; i < 10; i++) { peels.add(new Peel<>()); } System.out.println(peels); } } ``` ### 方法三:通过反射创建数组 可以使用 `Array.newInstance` 方法结合反射来创建数组。示例代码如下: ```java import java.lang.reflect.Array; class Peel<T> {} class Banana {} public class GenericArrayReflection { public static <T> T[] createArray(Class<T> clazz, int size) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, size); return array; } public static void main(String[] args) { Peel<Banana>[] peels = createArray(Peel.class, 10); System.out.println(peels.length); } } ```
### Java 数组构造的限制及其原因 Java 中不允许直接创建数组,这一限制的根本原因在于 **类擦除** 和运行时类检查的机制。以下是详细的分析: #### 1. 类擦除的影响 在 Java 中,是通过 **类擦除** 实现的。这意味着在编译后,信息会被移除,所有参数都会被替换为它们的上界(通常是 `Object`)。例如,`List<String>` 在运行时会被视为普通的 `List`[^2]。因此,当尝试创建一个数组时,编译器无法确定实际的类信息,这导致了运行时类不安全的问题。 #### 2. 运行时类检查的失效 Java数组在运行时会进行严格的类检查。例如,以下代码会导致 `ArrayStoreException`: ```java Object[] objArray = new String[1]; objArray[0] = new Integer(42); // 抛出 ArrayStoreException ``` 然而,对于 `Pair<Employee>`,由于类擦除的存在,运行时无法区分 `Pair<Employee>` 和 `Pair<Object>`。如果允许创建数组,则可能导致违反类的约束,从而破坏类安全性。例如: ```java Pair<Employee>[] pairArray = (Pair<Employee>[]) new Pair<?>[10]; // 编译时警告,但不会抛出异常 pairArray[0] = new Pair<Employee>(); // 如果可以将其他类的 Pair 放入数组中,就会导致问题 ``` 上述代码可能会导致运行时错误,因为类检查机制在数组中无法正常工作[^3]。 #### 3. 替代方案 尽管不能直接创建数组,但可以通过一些技巧实现类似的功能。以下是几种常见的替代方法: - **使用 `Object[]` 并进行显式类转换** 可以将数组声明为 `Object[]`,并在获取元素时进行类转换。这是 `ArrayList` 的实现方式之一: ```java public class ArrayList<E> { private Object[] elements; @SuppressWarnings("unchecked") public E get(int n) { return (E) elements[n]; } } ``` 这种方式虽然避免了直接创建数组,但在类安全性上依赖于开发者正确地使用类转换。 - **借助 `Array.newInstance`** 如果需要动态创建数组,可以使用反射机制中的 `Array.newInstance` 方法。例如: ```java @SuppressWarnings("unchecked") public static <T> T[] createGenericArray(Class<T> clazz, int size) { return (T[]) Array.newInstance(clazz, size); } ``` 注意,这种方式要求提供具体的类对象(如 `String.class` 或 `Integer.class`),并且仍然存在类擦除的风险。 - **使用包装类** 可以通过创建一个包装类来模拟数组的行为,同时保持的安全性。例如: ```java class GenericArray<T> { private Object[] array; public GenericArray(int size) { array = new Object[size]; } public void put(int index, T item) { array[index] = item; } @SuppressWarnings("unchecked") public T get(int index) { return (T) array[index]; } } ``` 然而,这种方式在尝试返回内部数组时可能会抛出 `ClassCastException`,因为底层仍然是 `Object[]`[^4]。 #### 总结 Java 不允许直接创建数组的原因主要归结于 **类擦除** 和 **运行时类检查机制** 的限制。为了避免潜在的类安全性问题,建议使用替代方案,如 `Object[]` 配合类转换、反射机制或包装类。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值