補(bǔ)充上篇
AbstractCollection < E >
在正式List之前,我們先了解我們補(bǔ)充上篇Collection接口的拓展實(shí)現(xiàn),也就是說(shuō)當(dāng)我我們需要實(shí)現(xiàn)一個(gè)不可修改的Collection的時(shí)候,我們只需要拓展某個(gè)類,也就是AbstractCollection這個(gè)類,他是Collection接口的骨干實(shí)現(xiàn),并以最大限度的實(shí)現(xiàn)了減少此接口所需要的工作;
如上兩圖進(jìn)行比較即可。
我們可以拓展Collection,然后提供iterator和size方法的實(shí)現(xiàn)即可,其中我們的iterator方法返回迭代器必須實(shí)現(xiàn)一個(gè)hasNext和next。
注意:
-
AbstractCollection<E>
是一個(gè)抽象類,不能直接實(shí)例化。如果需要使用它的方法,需要?jiǎng)?chuàng)建一個(gè)繼承自它的子類,并實(shí)現(xiàn)Collection<E>
接口中的所有方法。 -
AbstractCollection<E>
提供了size()和isEmpty()方法的默認(rèn)實(shí)現(xiàn),但是它們都是基于iterator()方法實(shí)現(xiàn)的。如果子類有更高效的實(shí)現(xiàn)方式,可以重寫(xiě)這些方法。 -
AbstractCollection<E>
提供了contains(Object o)和remove(Object o)方法的默認(rèn)實(shí)現(xiàn),但是它們都是基于iterator()方法實(shí)現(xiàn)的。如果子類有更高效的實(shí)現(xiàn)方式,可以重寫(xiě)這些方法。 -
AbstractCollection<E>
沒(méi)有提供add(E e)
和addAll(Collection<? extends E> c)
方法的默認(rèn)實(shí)現(xiàn),因?yàn)檫@些方法的實(shí)現(xiàn)方式可能因子類而異。如果子類需要實(shí)現(xiàn)這些方法,需要自行實(shí)現(xiàn)。 -
AbstractCollection<E>
提供了clear()和toArray()方法的默認(rèn)實(shí)現(xiàn),但是它們都是基于iterator()方法實(shí)現(xiàn)的。如果子類有更高效的實(shí)現(xiàn)方式,可以重寫(xiě)這些方法。 -
AbstractCollection<E>
提供了toString()方法的默認(rèn)實(shí)現(xiàn),但是它只是簡(jiǎn)單地將集合中的元素轉(zhuǎn)換為字符串并拼接在一起。如果子類需要更復(fù)雜的字符串表示方式,可以重寫(xiě)這個(gè)方法。
補(bǔ)充:
要實(shí)現(xiàn)一個(gè)可以修改的Collection,我們必須重新add方法,不然就會(huì)拋出異常,UnsupportedOperationException
,iterator 方法返回的迭代器還必須另外實(shí)現(xiàn)其 remove 方法。
List
List是java中有序的、允許重復(fù)的、值可以為NULL的。用戶可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問(wèn)元素,并搜索列表中的元素。
List 接口在 iterator、add、remove、equals 和 hashCode 方法的協(xié)定上加了一些其他約定,超過(guò)了 Collection 接口中指定的約定。
List接口中的元素按照插入順序排列,并且允許包含重復(fù)元素。
-
void add(int index, E element)
: 在指定位置插入指定元素。 -
boolean remove(Object element)
: 移除指定元素的第一個(gè)匹配項(xiàng)。 -
E remove(int index)
: 移除指定位置的元素。 -
E get(int index)
: 返回指定位置的元素。 -
E set(int index, E element)
: 替換指定位置的元素。 -
int indexOf(Object element)
: 返回指定元素第一次出現(xiàn)的位置。 -
int lastIndexOf(Object element)
: 返回指定元素最后一次出現(xiàn)的位置。 -
List<E> subList(int fromIndex, int toIndex)
: 返回指定范圍的子列表。
List接口有多個(gè)實(shí)現(xiàn)類,常見(jiàn)的有ArrayList、LinkedList和Vector等。
-
ArrayList是基于動(dòng)態(tài)數(shù)組實(shí)現(xiàn)的,它支持快速隨機(jī)訪問(wèn)和高效的插入、刪除操作。適用于頻繁訪問(wèn)元素的場(chǎng)景。
-
LinkedList是基于雙向鏈表實(shí)現(xiàn)的,它支持高效的插入、刪除操作,但訪問(wèn)元素的效率較低。適用于頻繁插入、刪除元素的場(chǎng)景。
-
Vector是線程安全的,它與ArrayList類似,但是性能較低。在多線程環(huán)境下,可以使用Vector來(lái)保證線程安全。
public class ListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 添加元素
list.add("apple");
list.add("banana");
list.add("orange");
// 獲取元素
String firstElement = list.get(0);
System.out.println("First element: " + firstElement);
// 修改元素
list.set(1, "grape");
// 刪除元素
list.remove("orange");
// 遍歷元素
for (String element : list) {
System.out.println(element);
}
// 判斷元素是否存在
boolean contains = list.contains("apple");
System.out.println("Does list contain 'apple'? " + contains);
// 獲取列表的大小
int size = list.size();
System.out.println("List size: " + size);
// 獲取子列表
List<String> subList = list.subList(0, 2);
System.out.println("Sublist: " + subList);
}
}
AbstractList
AbstractList
是List接口的一個(gè)抽象實(shí)現(xiàn)類,它提供了List接口中的一些通用實(shí)現(xiàn),使得實(shí)現(xiàn)List接口的子類可以更加方便地實(shí)現(xiàn)自己的方法。如下圖所示:
注意事項(xiàng):
-
AbstractList是一個(gè)抽象類,不能直接實(shí)例化。如果需要使用它的方法,需要?jiǎng)?chuàng)建一個(gè)繼承自它的子類,并實(shí)現(xiàn)List接口中的所有方法。
public class MyList<E> extends AbstractList<E> {
private Object[] elements;
private int size;
public MyList(int initialCapacity) {
elements = new Object[initialCapacity];
size = 0;
}
@Override
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return (E) elements[index];
}
@Override
public int size() {
return size;
}
@Override
public boolean add(E element) {
if (size == elements.length) {
resize();
}
elements[size++] = element;
return true;
}
@Override
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
E removedElement = (E) elements[index];
for (int i = index; i < size - 1; i++) {
elements[i] = elements[i + 1];
}
elements[--size] = null;
return removedElement;
}
private void resize() {
int newCapacity = elements.length * 2;
Object[] newElements = new Object[newCapacity];
System.arraycopy(elements, 0, newElements, 0, size);
elements = newElements;
}
}
在上述代碼中 我們創(chuàng)建了一個(gè)名為MyList
的類,它繼承自AbstractList
類,并實(shí)現(xiàn)了get(int index)、size()、add(E element)和remove(int index)
方法。
get(int index)
方法用于獲取指定索引位置的元素。我們?cè)诜椒ㄖ羞M(jìn)行了邊界檢查,并將元素強(qiáng)制轉(zhuǎn)換為泛型類型。size()
方法返回列表的大小。
add(E element)
方法用于向列表末尾添加元素。如果列表已滿,我們會(huì)調(diào)用resize()方法來(lái)擴(kuò)容。
remove(int index)
方法用于移除指定索引位置的元素。我們?cè)诜椒ㄖ羞M(jìn)行了邊界檢查,并將被移除的元素返回。移除元素后,我們需要將后面的元素向前移動(dòng),并將最后一個(gè)位置置為null。
ArrayList
這個(gè)在我們面試過(guò)程中經(jīng)常會(huì)碰到。
下面我們圍繞ArrayList進(jìn)行相關(guān)介紹:
- ArrayList作為Java中最常用的動(dòng)態(tài)數(shù)組實(shí)現(xiàn),他實(shí)現(xiàn)了List接口,由上圖可以見(jiàn)到,其繼承的AbstractList類實(shí)現(xiàn)的List接口,他可以動(dòng)態(tài)地增加或者刪除元素。注意一下他底層是數(shù)組,并且是可以擴(kuò)充的數(shù)組。既然他是數(shù)組實(shí)現(xiàn)的,我們都知道如果是數(shù)組元素,那么隨機(jī)訪問(wèn)速度會(huì)很快,但有優(yōu)點(diǎn)就有缺點(diǎn),查詢速度快了,那么刪除或者插入就慢,我們?cè)贏rrayList中插入或者刪除元素的時(shí)候需要移動(dòng)后面的元素,從而導(dǎo)致他的速度慢。
- ArrayList是非線程安全的,如果需要在多線程環(huán)境下使用,需要進(jìn)行同步處理。
- ArrayList的默認(rèn)初始容量為10,如果需要存儲(chǔ)更多的元素,可以在創(chuàng)建ArrayList對(duì)象時(shí)指定初始容量。
ArrayList 的擴(kuò)容機(jī)制
既然說(shuō)到了ArrayList的擴(kuò)容,那么我們來(lái)了解一下ArrayList的擴(kuò)容機(jī)制吧:
-
初始容量:當(dāng)創(chuàng)建一個(gè)新的ArrayList對(duì)象時(shí),它會(huì)分配一個(gè)初始容量。默認(rèn)情況下,初始容量為10,但也可以通過(guò)構(gòu)造函數(shù)指定其他初始容量。
-
容量增長(zhǎng):當(dāng)ArrayList的元素?cái)?shù)量超過(guò)當(dāng)前容量時(shí),ArrayList會(huì)自動(dòng)增加其容量。容量增長(zhǎng)的策略是通過(guò)創(chuàng)建一個(gè)更大的數(shù)組,并將原始數(shù)組中的元素復(fù)制到新數(shù)組中來(lái)實(shí)現(xiàn)的。
-
增長(zhǎng)因子:ArrayList的容量增長(zhǎng)是按照增長(zhǎng)因子來(lái)計(jì)算的。增長(zhǎng)因子是一個(gè)大于1的值,用于確定新容量相對(duì)于當(dāng)前容量的增長(zhǎng)量。默認(rèn)情況下,增長(zhǎng)因子為1.5,這意味著新容量將是當(dāng)前容量的1.5倍,比如說(shuō)10,經(jīng)過(guò)一次擴(kuò)容為 10 * 1.5 = 15。
-
擴(kuò)容操作:當(dāng)需要擴(kuò)容時(shí),ArrayList會(huì)創(chuàng)建一個(gè)新的數(shù)組,并將原始數(shù)組中的元素復(fù)制到新數(shù)組中。這個(gè)操作涉及到數(shù)組的復(fù)制,因此在擴(kuò)容時(shí)會(huì)有一定的性能開(kāi)銷。
-
擴(kuò)容策略:ArrayList的擴(kuò)容策略是相對(duì)保守的,它會(huì)盡量避免頻繁的擴(kuò)容操作。當(dāng)需要擴(kuò)容時(shí),ArrayList會(huì)根據(jù)當(dāng)前容量和增長(zhǎng)因子計(jì)算出一個(gè)新的容量,然后將新容量設(shè)置為ArrayList的容量。這樣做的目的是為了減少擴(kuò)容操作的頻率,提高性能。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-809333.html
代碼示例
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)ArrayList對(duì)象
ArrayList<String> list = new ArrayList<>();
// 向ArrayList中添加一個(gè)元素
list.add("apple");
list.add("banana");
// 在指定位置插入一個(gè)元素
list.add(1, "orange");
// 刪除指定位置的元素
list.remove(1);
// 刪除指定元素
list.remove("apple");
// 獲取指定位置的元素
String fruit = list.get(0);
// 替換指定位置的元素
list.set(0, "orange");
// 獲取ArrayList中元素的數(shù)量
int size = list.size();
// 清空ArrayList中的所有元素
list.clear();
// 判斷ArrayList中是否包含指定元素
boolean containsApple = list.contains("apple");
// 獲取指定元素在ArrayList中的位置
int index = list.indexOf("banana");
}
}
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-809333.html
到了這里,關(guān)于java基礎(chǔ) -02java集合之 List,AbstractList,ArrayList介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!