你好!在上一節課中,我們熟悉了這個
我們已經提到從普通數組中刪除元素不是很方便。由於我們不能刪除元素本身,我們只能將其值“清零”(設置為 null):
ArrayList
類,並學習瞭如何用這個類進行最常見的操作。此外,我們指出了數組ArrayList
和普通數組之間的幾個區別。但是我們繞過了一個話題,即如何從ArrayList
. 我們現在就來討論。 
public class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public static void main(String[] args) {
Cat[] cats = new Cat[3];
cats[0] = new Cat("Thomas");
cats[1] = new Cat("Behemoth");
cats[2] = new Cat("Lionel Messi");
cats[1] = null;
System.out.println(Arrays.toString(cats));
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
輸出: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] 但是將數組元素設置為 null 會留下一個“洞”。我們沒有刪除數組中的位置,只有它的內容。想像一下,如果我們有一個包含 50 隻貓的數組並以這種方式移除其中的 17 只,會發生什麼情況。我們將有一個有 17 個孔的陣列。試著跟踪他們!期望記住可以寫入新值的空單元格的數量是不現實的。如果你犯了一個錯誤,你將覆蓋你想要的對象引用。當然,有一種更仔細的方法:刪除元素後,將元素移動到數組的前面,將“孔”放在末尾:
public static void main(String[] args) {
Cat[] cats = new Cat[4];
cats[0] = new Cat("Thomas");
cats[1] = new Cat("Behemoth");
cats[2] = new Cat("Lionel Messi");
cats[2] = new Cat("Fluffy");
cats[1] = null;
for (int i = 2; i < cats.length-1; i++) {
cats [i-1] = cats [i];// Move the elements to the front of the array, so the empty position is at the end
}
System.out.println(Arrays.toString(cats));
}
Output: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] 這看起來更好,但很難稱為穩健的解決方案。如果不是因為我們每次從數組中刪除一個元素時都必須編寫這段代碼的話!這是一個糟糕的選擇。我們可以換一種方式創建一個單獨的方法:
public void deleteCat(Cat[] cats, int indexToDelete) {
//...delete the cat corresponding to the index and move the elements
}
但這也沒什麼用:這種方法只能對對象起作用Cat
,對其他類型不起作用。換句話說,如果一個程序有另外 100 個我們想要與數組一起使用的類,我們將不得不在每個類中使用完全相同的邏輯編寫相同的方法。這是一場徹底的災難-_-但是ArrayList
班級解決了這個問題!它實現了一種用於刪除元素的特殊方法:remove()
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.toString());
cats.remove(1);
System.out.println(cats.toString());
}
我們將對象的索引傳遞給刪除它的方法(就像在數組中一樣)。該remove()
方法有兩個特點。一是不留“洞”。它已經實現了當元素從中間移除時移動元素所需的邏輯,這是我們之前自己編寫的。查看前面代碼的輸出:
[Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
我們從中間移走了一隻貓,其餘的都移動了,這樣就沒有空位了。 其次,它不僅可以通過索引(如普通數組)刪除對象,還可以通過引用刪除對象:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.toString());
cats.remove(lionel);
System.out.println(cats.toString());
}
輸出: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] 如果您不想始終跟踪所需對象的索引,這會非常方便。看來我們已經想通了普通的刪除。現在讓我們想像一下這種情況:我們想要遍歷列表並刪除具有特定名稱的貓。為此,我們將使用快速for
循環(也稱為 for-each 循環),這是我們在 Rishi 的課程中介紹的:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
for (Cat cat: cats) {
if (cat.name.equals("Behemoth")) {
cats.remove(cat);
}
}
System.out.println(cats);
}
該代碼看起來非常合乎邏輯。但結果可能是一個很大的驚喜: Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList. java:831) at Cat.main(Cat.java:25) 出現了某種錯誤,目前還不清楚為什麼會發生。此過程涉及許多必須解決的細微差別。以下是您需要記住的一般規則: 您不能同時迭代一個集合併更改其元素。 我們指的是任何形式的改變,而不僅僅是移除。如果你用嘗試插入新的貓來替換貓的移除,結果將是相同的:
for (Cat cat: cats) {
cats.add(new Cat("Salem Saberhagen"));
}
System.out.println(cats);
java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) 在 java.util.ArrayList$Itr.next(ArrayList.java:831) 在 Cat.main( Cat.java:25) 我們將一個操作更改為另一個操作,但結果沒有改變:我們得到相同的ConcurrentModificationException。當我們嘗試通過在遍歷列表的同時更改列表來打破上述規則時,它就會發生。在 Java 中,我們需要一個稱為迭代器(的特殊對象Iterator
來在迭代集合時刪除項目。該類Iterator
負責安全地迭代元素列表。它非常簡單,因為它只有 3 個方法:
hasNext()
- 返回 true 或 false,取決於列表中是否有下一項,或者我們已經到達最後一項。next()
- 返回列表中的下一項remove()
- 從列表中刪除一個項目
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list
Cat nextCat = catIterator.next();// Get the next element
System.out.println(nextCat);// Display it
}
輸出: Cat{name='Thomas'} Cat{name= ' Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} 如您所見,ArrayList
迭代器:iterator()
. 此外,請注意,當我們創建迭代器時,我們指定了它將使用的對像類 ( <Cat>
)。底線是迭代器可以輕鬆處理我們的原始任務。例如,刪除名為“Lionel Messi”的貓:
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list
Cat nextCat = catIterator.next();// Get the next element
if (nextCat.name.equals("Lionel Messi")) {
catIterator.remove();// Delete the cat with the specified name
}
}
System.out.println(cats);
輸出: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}]remove()
您可能已經註意到我們沒有在迭代器的方法 中指定索引或名稱!迭代器比它看起來更聰明:remove()
刪除迭代器返回的最後一個元素。如您所見,它完成了我們希望它完成的工作:) 原則上,這就是您需要了解的有關從ArrayList
. 好吧,幾乎所有的東西。在下一課中,我們將深入了解這個類,看看在各種方法調用期間那裡發生了什麼 :) 在那之前!
GO TO FULL VERSION