[英]Move Elements In An ArrayList Down One That Are Higher Than Specific Index
我有一個服務器,當客戶機加入時,該服務器創建一個新線程並將其放入ArrayList(類型為EchoThread)中。 它的工作原理非常好-為每一個創建一個新的JLabel並立即更新它們在我的游戲中的位置,但是,如果一個離開(不是arraylist中的最后一個客戶端),那么我希望服務器移動所有客戶端(那個比剩下的客戶索引高1。 我嘗試了很多事情,有些工作了。 這是有人離開的方法,其中i等於離開的客戶的索引:
public static void removeClient(int i) throws Exception {
}
我嘗試了幾件事,例如使用for循環將arrayList中的每個EchoThread向下移動一個,但是它們似乎不起作用:
ArrayList:
static ArrayList<EchoThread> clients = new ArrayList<EchoThread>();
我嘗試過的for循環:
for(int ii = i+1; ii < clients.size()-1; ii++){
EchoThread e = clients.get(ii);
clients.set(ii-1, e);
}
我還嘗試制作一個臨時數組列表,該數組將添加客戶端數組列表中除索引i之外的所有元素,然后將客戶端數組列表設置為等於臨時數組列表,但是仍然失敗。
有人說我可以使用鏈表,但是我不知道怎么辦?
編輯:
p = a JPanel
f = a JFrame
clients = an arrayList<EchoThread>
clientinfo = a JLabel in EchoThread class
clientname = an arraylist of strings
clientpos = an arraylist of the positions of each client
info = a JLabel to show number of clients that are connected
方法:
public static void removeClient(int i) throws Exception {
p.remove(clients.get(i).clientinfo);
p.revalidate();
f.validate();
f.repaint();
clients.get(i).clientinfo.setVisible(false);
clients.remove(i);
clientnames.remove(i);
clientpos.remove(i);
info.setText("Clients Connected: " + clients.size());
for(int ii = i+1; ii < clients.size()-1; ii++){
EchoThread e = clients.get(ii);
clients.set(ii-1, e);
}
}
您是否嘗試過clients.remove(i);
這是ArrayList#remove
的實現。 如您所見,它使用System.arraycopy向下滑動列表的尾部,因此您可以得到不間斷的列表。
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
API已經使用remove
方法為您完成了此操作。
來自文檔:
公共E remove(int索引)
刪除此列表中指定位置的元素。 將所有后續元素向左移動(從其索引中減去一個)。
您必須確保以線程安全的方式調用removeClient。 我正在猜測,但是聽起來好像您是從每個EchoThread調用它的,沒有同步就不安全,因為(a) 線程可以踐踏彼此對列表的所有修改 ; (b) 無法保證線程甚至不會看到彼此對列表的修改 。
通常,您可以只在修改ArrayList的任何方法上添加synchronized
修飾符 ,該方法既提供互斥(防止多個線程立即對其進行修改並破壞),又提供了對這些方法的調用之間的事前關系(確保線程看到對方對列表的更改)。 但是,這還不夠,因為您還使用該方法來修改Swing組件。 除少數例外,必須僅從單個事件分發線程訪問Swing組件,因此,如果要更新框架並且您位於其他線程上,則必須首先切換到事件分發線程。
在Java 8+中,按如下所示修改removeClient方法的開頭:
public static void removeClient(int i) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(() -> removeClient(i));
return;
}
// ...
在舊版本的Java中:
public static void removeClient(final int i) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
removeClient(i);
}
});
return;
}
// ...
一旦您位於正確的線程上,從列表中刪除該項目並將其他項目移到該列表中實際上就像調用clients.remove(i);
一樣簡單clients.remove(i);
,就像其他答復者所說的那樣。 您不需要額外的for循環,它將無法正常工作。
也許您的問題是,盡管列表確實將項目下移,但是您已為這些項目提供了自己的索引字段,因此在刪除項目后,其自身的索引字段不再與列表中的實際位置匹配? 您可以迭代列表中的項目,並重置每個項目的索引字段以匹配其實際位置:
for (int i = 0; i < clients.size(); i++)
clients.get(i).index = i;
(假設您在EchoThread對象上有一些字段index
)。
但是,這可能不是最佳方法。 你不一定需要保持指數的跟蹤,因為你可以非常清楚刪除對象本身不知道指數:
EchoThread client = ...;
clients.remove(client);
如何更新您的其他列表, clientnames
, clientpos
? 好了,您可以通過在第一個列表上調用indexOf
來找到索引。 但這很丑。 您不應該真正擁有所有這些單獨的列表。 您最好具有一個類,該類封裝單個客戶端的各種不同字段,包括“名稱”和“ pos”字段,並列出這些對象。 您已經有了EchoClient對象,因此也許您可以將字段移至該對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.