Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 泛型列表数组_Java_Generics - Fatal编程技术网

Java 泛型列表数组

Java 泛型列表数组,java,generics,Java,Generics,我在玩泛型和数组,似乎下面的代码编译得很好 ArrayList<Key> a = new ArrayList<Key>(); ArrayList a=新的ArrayList(); 但是编译器抱怨这一点 ArrayList<Key>[] a = new ArrayList<Key>[10]; ArrayList[]a=新的ArrayList[10]; 通过阅读stackoverflow中的post,我了解到这是由于类型擦除造成的,我可以使用

我在玩泛型和数组,似乎下面的代码编译得很好

ArrayList<Key> a = new ArrayList<Key>();
ArrayList a=新的ArrayList();
但是编译器抱怨这一点

ArrayList<Key>[] a = new ArrayList<Key>[10];
ArrayList[]a=新的ArrayList[10];
通过阅读stackoverflow中的post,我了解到这是由于类型擦除造成的,我可以使用

ArrayList<Key>[] a = (ArrayList<Key> []) new ArrayList[10];
ArrayList[]a=(ArrayList[])新的ArrayList[10];
或列表

ArrayList<ArrayList<Key>> b = new ArrayList<ArrayList<Key>>();
ArrayList b=新的ArrayList();

但我想不出幕后的原因。特别是,考虑到第一个问题,为什么第二个问题是非法的是完全可以的。以及为什么编译器不抱怨列表的列表。

您不能拥有数组,因为数组需要原始类型。您可以在第二个实例中对其进行类型转换,这使其符合定义的类型,因此是合法的(但是,这是无法推断的)。列表列表是合法的,因为
ArrayList
不是数组

请参阅中的第7.3章(第15页),以了解有关这方面的更多详细信息

数组对象的组件类型不能是类型变量或 参数化类型,除非它是(无界)通配符类型。您可以 声明其元素类型为类型变量或 参数化类型,但不是数组对象。 当然,这很烦人。此限制对于避免以下情况是必要的:

List<String>[] lsa = new List<String>[10]; // not really allowed
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li; // unsound, but passes run time store check
String s = lsa[1].get(0); // run-time error - ClassCastException
List[]lsa=新列表[10];//不允许
对象o=lsa;
对象[]oa=(对象[])o;
List li=new ArrayList();
加(新整数(3));
oa[1]=li;//不可靠,但通过运行时存储检查
字符串s=lsa[1]。获取(0);//运行时错误-ClassCastException
如果允许参数化类型的数组,则上面的示例将 编译时没有任何未检查的警告,但在运行时失败

本教程接着介绍以下内容:

由于类型变量在运行时不存在,因此无法确定 实际数组类型为。 解决这些限制的方法是使用类文本作为运行时 类型标记


数组允许逃避类型检查(如Chris的回答所示)。所以,您可以有一个通过所有编译器检查的代码(没有来自编译器的“未检查”警告),但在运行时由于ClassCastException而失败。 禁止这种构造会给开发人员带来问题,因此警告确实会出现。

我有一个自己的FWIW,我觉得答案没有说服力。最详细答案的相关部分(参考pdf参考)如下:

数组对象的组件类型不能是类型变量或 参数化类型,除非它是(无界)通配符类型。您可以 声明其元素类型为类型变量或 参数化类型,但不是数组对象。老实说,这很烦人 当然此限制对于避免以下情况是必要的:

List[]lsa=新列表[10];//不允许
对象o=lsa;
对象[]oa=(对象[])o;
List li=new ArrayList();
加(新整数(3));
oa[1]=li;//不可靠,但通过运行时存储检查
字符串s=lsa[1]。获取(0);//运行时错误-ClassCastException
因此,因为我可以将列表[]cat到对象[],然后将不正确的内容推入对象[],然后从列表引用中通过casted ref错误引用,这是坏的/不允许的?但只有新的吗


对于我来说,用new来声明这一点与用法相比或多或少是一个问题,这一点仍然有点模糊,我仍然盯着它看,希望它开始有意义,或者至少能解析成一个漂亮的3d图像。

创建通用数组不是类型安全的(请参阅约书亚·布洛赫的《有效的Java——第二版》

使用:

List b=新的数组列表(10);
或使用Java SE 7:

 List<List<Key>> b = new ArrayList<>(10);
List b=新的数组列表(10);

数组是穷人的泛型;对于真正的泛型,人们应该避免使用数组,尽管并不总是可能的

数组是协变的,泛型是不变的;再加上擦除,情况就不太适合了,正如Chris回答中的示例所示

不过,我认为可以放宽规范,允许创建泛型数组-这真的没有问题。当抛出数组时,危险就来了;此时一个编译器警告就足够了

实际上Java确实为vararg方法创建了泛型数组,所以这有点虚伪

下面是利用这一事实的实用方法

@SafeVarargs
static <E> E[] arrayLiteral(E... array)
{
    return array;
}

@SafeVarargs
static <E> E[] newArray(int length, E... array)
{
    return Arrays.copyOf(array, length);
}

// usage

    List<String>[] array1 = arrayLiteral(list, list);

    List<String>[] array2 = newArray(10);
@SafeVarargs
静态E[]阵列并行(E…阵列)
{
返回数组;
}
@安全变量
静态E[]新数组(整数长度,E…数组)
{
返回数组.copyOf(数组,长度);
}
//用法
列表[]数组1=数组并行(列表,列表);
列表[]数组2=newArray(10);

编译器需要保证泛型类型安全;如果不能,则必须禁用代码或发出警告。在本例中,第2行的警告似乎足够了;java完全禁用泛型数组创建的决定似乎过于苛刻。是
ArrayList[]a=(ArrayList[])new ArrayList[10]
仍然存在同样的问题,但这更清楚地表明您在欺骗类型系统(并生成警告)。finnw,您的评论是我认为正确的答案,也是唯一对我有意义的方法。这可能是因为向后兼容。假设某个未来版本(Java 9?)允许创建通用数组,然后当Java 9代码与Java 5/6/7/8代码混合时(可以在没有警告的情况下向上转换数组),结果将是意外的ClassCastException。请注意,在这些代码示例中,创建的数组的实际类型不是
E[]
,但删除某些推断类型的
E
。例如,如果执行
静态T[]m(){T[]a=newArray(0);返回a;}
,则为
a的实际类型
 List<List<Key>> b = new ArrayList<>(10);
@SafeVarargs
static <E> E[] arrayLiteral(E... array)
{
    return array;
}

@SafeVarargs
static <E> E[] newArray(int length, E... array)
{
    return Arrays.copyOf(array, length);
}

// usage

    List<String>[] array1 = arrayLiteral(list, list);

    List<String>[] array2 = newArray(10);