首页 > 解决方案 > 列表覆盖 toArray 最终为 T1[] toArray

问题描述

我试图通过在一个类中实现 List 接口来稍微调整一个 List。

我可以毫无问题地覆盖和实现所有方法,除了这个:

<T> T[] toArray(T[] a);

Android Studio 在覆盖时向我展示了这段代码,创建了一个新类型T1。为什么会这样,它有什么影响?

@NonNull
@Override
public <T1> T1[] toArray(@NonNull T1[] a) {
    return inner.toArray(a);
}

将鼠标悬停在a参数上时,我看到以下 lint 警告:

java.lang.Object预期类型的​​数组

当我尝试手动将其更改回T[]而不是出现T1[]此错误时:

'QueryList' 中的 toArray(T[])' 与 'java.util.List' 中的 'toArray(T[])' 冲突;两种方法都有相同的擦除,但都没有覆盖另一个

这是 Android Studio/intelliJ 中的一个错误,它无法正确创建该覆盖,还是我错过了什么?

编辑: 这是类的声明,包括T它的使用位置和位置。

public class QueryList<T> implements List<T> {

//<editor-fold desc="inner list & constructors">
protected final List<T> inner;

public QueryList() {
    inner = new ArrayList<>();
}

public QueryList(int initialCapacity) {
    inner = new ArrayList<>(initialCapacity);
}

public QueryList(@NonNull Collection<? extends T> c) {
    inner = new ArrayList<>(c);
}
//</editor-fold>

谢谢你的帮助。

标签: javaandroid

解决方案


不涉及其他 T

您的QueryList类声明了一个类型参数,该参数也名为T,因此 intellij 可能会将覆盖中的参数重命名为T1以明确显示它是不同的。

请注意,toArrayinList还声明了它自己的类型参数,这也是正确覆盖所必需的:

<T> T[] toArray(T[] a);
^^^

我猜你的修复也像这样删除了类型参数声明:

T[] toArray(T[] a);

但这将不再使其成为覆盖,因为类型参数必须匹配。根据jls 8.4.8.1

在类 C 中声明或继承的实例方法 mC,从 C 覆盖在类 A 中声明的另一个方法 mA,如果以下所有条件都为真:

...

并在8.4.2

如果两个方法或构造函数 M 和 N 具有相同的名称、相同的类型参数(如果有) (第 8.4.4 节),并且在将 N 的形式参数类型调整为类型参数后,则它们具有相同的签名的 M,形参类型相同。

并且子签名的概念在强调的部分也不再宽松。


当我将其更改为 时<T> T[] toArray(T[] a);,我会收到一条警告,指出在T那里声明的类型参数隐藏了封闭类中的那个,但将名称更改为T1使其消失。

至于为什么签名是这样的,一种解释是您想使用超类型数组来收集列表的元素。例如:

class A {}
class B extends A {}

List<B> list = ...
A[] elements = list.toArray(new A[0]); // should still work, no need to pass a `B[]` strictly.

推荐阅读