我正在尝试构建自己的 JCF(玩弄以更好地理解集合)。
我创建了一个MyList<E>
实现接口的类,Collection<E>
因此有必要实现默认方法retainAll(Collection<?> c)
和<T> T[] toArray(T[] array)
.
好像发生了,但是想请教高手,在方法中是否可以通过<T> T[] toArray(T[] array)
其他方式创建一个新的更大的数组?
我试图创建一个新类型Object[]
,然后将其强制转换为T[]
,但它崩溃了ClassCastException
。
我的决定:
@Override
default boolean retainAll(Collection<?> c) {
removeIf(element -> !c.contains(element));
return true;
}
@Override
default <T> T[] toArray(T[] array) {
if (array.length != size()) {
array = Arrays.copyOf(array, array.length + (size() - array.length));
}
for (int i = 0; i < size(); i++)
array[i] = (T)get(i);
return array;
}
以一般形式创建参数化类型(泛型)的数组
您可以尝试使用反射创建一个数组
我们有
object
一个参数化类型(通用)T
:使用这些输入,我们可以创建一个给定类型的元素数组,如下所示:
toArray 方法的目的
创建该方法
toArray
是为了将集合转换为相同类型的数组。在这个方法中,我们传递一个对我们将要写入集合数据的数组的引用。
如果数组中没有足够的空间,那么我们创建一个新的并写入它来代替旧的。
如果数组中的空间多于所需空间,则我们将空元素 (
null
) 作为数据结束标记。考虑 toArray 方法的可用实现
为了正确实现此方法,最好看看他们自己如何建议这样做,使用来自
ArrayList
和的实现示例LinkedList
。ArrayList 类中 toArray(T[] a) 的实现
我提醒您,我们正在考虑 ArrayList 的实现,顾名思义,这是一个
List<E>
基于数组的接口的实现,这在进一步考虑的上下文中很重要。ArrayList
elementData 字段用于在类中存储列表的元素。首先,我们检查传递的数组是否足够大以将现有元素放入其中。
如果数组的大小不够,那么使用实用程序类,我们制作一个具有相同大小和传递数组类型的
Arrays
数组的副本( )elementData
a.getClass()
否则,我们将数组的所有元素复制
elementData
到数组中а
(按计划),从头开始(在这种情况下,使用的方法允许您指定开始复制的位置和复制到的位置,以及这些元素的数量)。我们使用类中的实用方法进行复制
arraycopy
System
接下来,我们检查传递的数组是否大于我们的列表。
如果传过来的数组比需要的大,那么我们把null放在复制元素的后面,这样在迭代的时候,可以找到数据的结尾,而不是抓脸的Exception
LinkedList 类中 toArray(T[] a) 的实现
和前面的例子一样,我们首先检查传递的数组的大小是否足够大。
如果数组的大小不足,则使用反射创建一个具有指定数据类型和所需大小的新数组,并将对它的引用保存在变量中
a
我注意到这个实现完全使用了我最初提出的方法。
与第一个实现不同,在这个阶段我们只有一个足够大小的空数组,而在前一个实现中,我们已经为一个处理过的案例返回了一个新数组。
接下来,我们需要将所有元素转移到这个数组中。
首先,我们定义一个变量来存储可迭代元素的索引,因为 在链表中,迭代时,我们只有前一个元素和下一个元素的链接。
接下来,我们创建一个变量
result
并在其中放置对数组的引用。a
这就是需要解释团队的地方。
这样做显然是为了不打扰类型转换。
因此,为了避免问题和麻烦,我们将简单地创建另一个链接,仅已声明为
Object[]
.并且我们已经被允许在没有任何类型转换的情况下放置列表的元素。
事实上,我们将使用相同的数组。
只是入坑的条件会比较软 :)
这种带耳朵的佯攻可以在源码中找到。
java.lang
实际上,开发者
JDK
只是把你列在清单上的责任推给你(他们还应该怎么做?) .接下来,我们使用变量将链表的元素复制到一个数组中
result
也值得在这里停下来更详细地考虑一切。
首先,我们将链表节点作为迭代器,并使用对第一个元素的引用来初始化迭代器。
作为退出循环的条件,我们使用通常的空值检查。
迟早,它会出现在那里,因为列表中的最后一个元素将具有指向列表中下一个元素的链接,并且等于
null
,我们将停在那里。好吧,作为转换表达式,我们使用获取到链表下一个元素的链接
因此,反过来,逐个元素地获取,我们将绕过整个列表。
并获取列表的每个元素,我们将其值放入数组中
а
此外,与第一个变体一样,我们用空元素标记数据的结尾
并返回一个数组
您的实施
首先,我将指出您实施的一些缺点。
这是复制数组时使用的内容:
为什么这么难?
如果我们省略括号(在这里它们是可选的),那么我们只得到
size()
(array.length - array.length = 0
)因为 我没有类的整个实现的代码,我不能为你完全写出你方法的某种终极实现
toArray
,也不能检查它的性能,但我可以看例子,注意在上述实现中使用的想法和技术,并提出了一些实现建议。选项
您可以用耳朵使用相同的技巧来更改数组的类型并编写如下内容:
我对它是否有效感兴趣。
你怎么试 - 退订!