欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?ArrayList實(shí)現(xiàn)刪除指定位置的元素

 更新時(shí)間:2023年01月09日 09:16:33   作者:海棠路  
目標(biāo):list中有0到39共40個(gè)元素,刪除其中索引是10、20、30的元素。本文為大家整理了三個(gè)不同的方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

目標(biāo):list中有0到39共40個(gè)元素,刪除其中索引是10、20、30的元素

方案一:使用普通for循環(huán)從前往后遍歷再刪除

//初始化List列表
List<String> list = new ArrayList<>();
for (int i = 0; i < 40; i++) {
    list.add("element" + i);
}

首先當(dāng)我們刪除第10位元素時(shí),List會(huì)將后面的元素向前補(bǔ)位,之后再查第10位元素就會(huì)輸出第11位元素

for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.get(10));

輸出:

element11

那么刪除了一個(gè)元素以后,后面需要?jiǎng)h除的元素位置就向前提1位

/**
 * 如果明確需要?jiǎng)h除元素的位置
 * 那么可以這樣,每刪除一個(gè)元素后就把下一個(gè)要?jiǎng)h除元素的位置減1
 * 注意這么做有個(gè)需要注意的點(diǎn),那就是每次刪除完節(jié)點(diǎn)后遍歷指針i需要減一,這樣在刪除兩個(gè)臨近節(jié)點(diǎn)時(shí)才不會(huì)出現(xiàn)問(wèn)題
 * 比如要?jiǎng)h除10和11
 */
for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
        i--;
    }
    if (i == 19) {
        list.remove(i);
        i--;
    }
    if (i == 28) {
        list.remove(i);
        i--;
    }
}

System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

輸出:

 false
 false
 false

當(dāng)然我們可以用一個(gè)數(shù)組或列表從小到大存儲(chǔ)需要?jiǎng)h除的位置,然后再for循環(huán)中進(jìn)行運(yùn)算和取值

方案二:使用普通for循環(huán)從后往前遍歷再刪除

從后向前遍歷的好處是我們不需要再像方案一一樣每刪除一個(gè)元素都需要去考慮后面元素向前補(bǔ)位的問(wèn)題

for (int i = list.size() - 1; i >= 0; i--) {
    if (i == 30) {
        list.remove(i);
    }
    if (i == 20) {
        list.remove(i);
    }
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

輸出:

 false
 false
 false

從后向前,即使后面進(jìn)行元素進(jìn)行向前補(bǔ)位操作也不會(huì)影響前面需要?jiǎng)h除的元素

這里也可以用一個(gè)數(shù)組或列表存儲(chǔ)需要?jiǎng)h除的元素,從大到小排列,取出一個(gè)刪除一個(gè)

方案三:使用迭代器刪除

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));

輸出:

element11
false

在迭代器中維護(hù)一個(gè)數(shù)字i標(biāo)識(shí)遍歷的位置

如果我們?cè)诘髦欣^續(xù)刪除另外20和30位置元素

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    if (i == 20) {
        iterator.remove();
    }
    if (i == 30) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));
System.out.println(list.get(20));
System.out.println(list.contains("element20"));
System.out.println(list.get(30));
System.out.println(list.contains("element30"));

輸出:

element11
false
element22
false
element33
false

首先我們?cè)诘^(guò)程中指定的是刪除10、20、30三個(gè)位置的元素,可以看到輸出contains時(shí)都是false表示正確刪除,但是最終輸出列表的值發(fā)現(xiàn)對(duì)應(yīng)索引位置已經(jīng)進(jìn)行了補(bǔ)位。

我們debug分析一下為什么

先簡(jiǎn)單介紹一下Iterator和Iterable

Iterable是一個(gè)迭代接口,實(shí)現(xiàn)了這個(gè)接口代表該類(lèi)可以迭代

可以看到我們的集合Collection接口就是它的子類(lèi)

它有一個(gè)主要方法:

// 返回一個(gè)實(shí)現(xiàn)了Iterator接口的對(duì)象,我們也是用這個(gè)對(duì)象去進(jìn)行迭代
Iterator<T> iterator();

Iterator,它主要有三個(gè)方法:

// 返回是否還有下一個(gè)元素
boolean hasNext();
// 返回下一個(gè)元素
E next();
// 刪除該元素
default void remove() {
    throw new UnsupportedOperationException("remove");
}

每個(gè)不同的集合類(lèi)都會(huì)有不同的Iterator接口實(shí)現(xiàn),在ArrayList中使用了一個(gè)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}
}

我們通過(guò)list.iterator()拿到的就是這個(gè)內(nèi)部類(lèi)的對(duì)象實(shí)例,這個(gè)類(lèi)中有兩個(gè)字段cursor和lastRet,這兩個(gè)字段就是我們能在迭代器中正確刪除對(duì)應(yīng)位置的元素的關(guān)鍵。

有關(guān)expectedModCount和modCount的問(wèn)題后面會(huì)補(bǔ)充,我們先不用關(guān)注

cursor初始化是0 lastRet初始化是-1

分析next和remove方法的源碼

/**
* 可以先不關(guān)注這兩個(gè)Exception
* 每次調(diào)用next() cursor都會(huì)+1 而lastRet就會(huì)變成之前cursor的值
* cursor初始化是0
* lastRet初始化是-1
* 調(diào)用一次以后  cursor是1 lastRet變成0
**/
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        // 調(diào)用本身的remove方法
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

關(guān)鍵是這個(gè)remove方法對(duì)cursor和lastRet的修改

假如正在刪除第10個(gè)元素

執(zhí)行remove方法前cursor應(yīng)該是11,lastRet是10

執(zhí)行了以后lastRet變成了-1,cursor變成了10

下次執(zhí)行next()方法返回的元素其實(shí)還是elementData[10]也就是List補(bǔ)位后正確的下一個(gè)元素,cursor變成了11,lastRet是10

總結(jié):使用迭代器遍歷時(shí)ArrayList會(huì)用lastRet和cursor兩個(gè)變量來(lái)維護(hù)當(dāng)前遍歷的元素索引和下一次需要遍歷元素的索引,通過(guò)這兩個(gè)變量就可以實(shí)現(xiàn)迭代中正確的刪除某個(gè)位置的元素。

到此這篇關(guān)于Java ArrayList實(shí)現(xiàn)刪除指定位置的元素的文章就介紹到這了,更多相關(guān)Java ArrayList刪除指定位置元素內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論