如何自定义集合类并继承 AbstractList/AbstractMap:从头开始实现一个自己的集合类!
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在 Java 中,AbstractList
和 AbstractMap
是 java.util
包中的两个抽象类,分别用于简化 List
和 Map
的自定义实现。如果你需要构建一个自定义的集合类,并且希望它符合 List
或 Map
的规范,可以继承这两个抽象类中的一个,来简化你的实现过程。今天我们将详细探讨如何继承 AbstractList
和 AbstractMap
来实现自定义集合类。
1. 继承 AbstractList
AbstractList
是 java.util.List
接口的一个抽象实现类,提供了一些 List
操作的默认实现,比如 size()
和 isEmpty()
。但是,你仍然需要实现其中的核心方法,如 get(int index)
、add(E element)
和 remove(int index)
。
1.1 继承 AbstractList
创建自定义列表
我们可以通过继承 AbstractList
来实现一个简单的自定义列表类。例如,假设我们想实现一个基于数组的简单列表。
示例代码:
import java.util.AbstractList;
public class MyArrayList<E> extends AbstractList<E> {
private Object[] elements;
private int size;
// 构造方法,初始化一个初始容量的数组
public MyArrayList(int capacity) {
elements = new Object[capacity];
size = 0;
}
@Override
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index out of bounds");
}
return (E) elements[index];
}
@Override
public int size() {
return size;
}
@Override
public boolean add(E e) {
if (size == elements.length) {
grow();
}
elements[size++] = e;
return true;
}
// 扩展数组大小
private void grow() {
int newCapacity = elements.length * 2;
Object[] newArray = new Object[newCapacity];
System.arraycopy(elements, 0, newArray, 0, elements.length);
elements = newArray;
}
@Override
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index out of bounds");
}
E oldValue = (E) elements[index];
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elements, index + 1, elements, index, numMoved);
}
elements[--size] = null; // 清空最后一个元素
return oldValue;
}
}
代码分析:
- 构造方法:
MyArrayList(int capacity)
用来初始化一个指定初始容量的数组。 - get(int index):返回指定索引位置的元素。如果索引越界,抛出
IndexOutOfBoundsException
异常。 - size():返回当前列表的大小。
- add(E e):向列表中添加元素。如果数组已满,调用
grow()
方法扩展数组。 - remove(int index):删除指定索引位置的元素,之后将后面的元素向前移动,保持数组的连续性。
AbstractList
为我们提供了许多有用的方法实现,比如 addAll()
、removeAll()
、clear()
等,因此只需要实现 get(int index)
、size()
和 remove(int index)
这些基本方法。
1.2 扩展:实现其他 List
操作
继承 AbstractList
后,我们还可以进一步覆盖和扩展其他操作,如插入元素、修改元素等。这些操作在 AbstractList
中有默认实现,通常需要根据自己的需求重写。
2. 继承 AbstractMap
AbstractMap
是 java.util.Map
接口的一个抽象实现类,用于简化 Map
的实现。你需要实现 get(Object key)
、put(K key, V value)
、remove(Object key)
和 size()
等核心方法。
2.1 继承 AbstractMap
创建自定义映射类
假设我们要实现一个简单的基于数组的 Map
类。
示例代码:
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
public class MyHashMap<K, V> extends AbstractMap<K, V> {
private Object[] keys;
private Object[] values;
private int size;
private static final int INITIAL_CAPACITY = 16;
// 构造函数,初始化键值对数组
public MyHashMap() {
keys = new Object[INITIAL_CAPACITY];
values = new Object[INITIAL_CAPACITY];
size = 0;
}
@Override
public V get(Object key) {
for (int i = 0; i < size; i++) {
if (keys[i].equals(key)) {
return (V) values[i];
}
}
return null; // 如果没有找到键,则返回null
}
@Override
public V put(K key, V value) {
if (size == keys.length) {
grow();
}
for (int i = 0; i < size; i++) {
if (keys[i].equals(key)) {
V oldValue = (V) values[i];
values[i] = value;
return oldValue;
}
}
keys[size] = key;
values[size] = value;
size++;
return null;
}
// 扩展数组大小
private void grow() {
int newCapacity = keys.length * 2;
Object[] newKeys = new Object[newCapacity];
Object[] newValues = new Object[newCapacity];
System.arraycopy(keys, 0, newKeys, 0, keys.length);
System.arraycopy(values, 0, newValues, 0, values.length);
keys = newKeys;
values = newValues;
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> entrySet = new HashSet<>();
for (int i = 0; i < size; i++) {
final int index = i;
entrySet.add(new AbstractMap.SimpleEntry<>( (K) keys[index], (V) values[index]));
}
return entrySet;
}
@Override
public int size() {
return size;
}
@Override
public V remove(Object key) {
for (int i = 0; i < size; i++) {
if (keys[i].equals(key)) {
V oldValue = (V) values[i];
System.arraycopy(keys, i + 1, keys, i, size - i - 1);
System.arraycopy(values, i + 1, values, i, size - i - 1);
keys[--size] = null;
values[size] = null;
return oldValue;
}
}
return null;
}
}
代码分析:
- 构造方法:
MyHashMap()
初始化了一个指定初始容量的键值对数组。 - get(Object key):遍历所有的键值对,找到对应键的值。如果不存在,返回
null
。 - put(K key, V value):将键值对存入数组。如果键已经存在,更新其值;否则,插入新键值对。
- grow():扩展键值对数组大小。
- entrySet():返回一个包含所有键值对的
Set
,通过AbstractMap.SimpleEntry
来包装每个键值对。 - size():返回
Map
中的元素数量。 - remove(Object key):删除指定键的键值对,并将后续元素前移。
2.2 扩展:实现其他 Map
操作
和 AbstractList
类似,AbstractMap
也为大部分操作提供了默认实现,因此你只需实现核心的几个方法,并根据需要扩展其他方法。
3. 总结
继承 AbstractList
和 AbstractMap
是实现自定义集合类的一个简单而高效的方式。通过继承这些抽象类,你可以专注于实现核心的操作,如元素的插入、删除、查找等,而不必重新实现一些常见的基础方法。你可以根据需要继续扩展或覆盖其他方法,以便完全满足自己的需求。
- 继承
AbstractList
:适合实现基于数组或链表的列表集合。 - 继承
AbstractMap
:适合实现基于数组、链表、哈希表等的映射集合。
无论是创建自定义的 List
还是 Map
,只要合理设计,便能创建出既高效又符合业务需求的集合类。这为你在开发过程中提供了极大的灵活性,帮助你处理各种复杂的场景。
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!
- 点赞
- 收藏
- 关注作者
评论(0)