2

について説明が必要java.util.listです。私は開発にEclipseを使用しています。
私はこのコードを書きました

public static void main(String[] asdf){
        List<Integer> lst = new ArrayList<Integer>();
        for(int i=0;i<10000;i++){
            lst.add(i);
        }

        System.out.println(lst.size());

        for(int i=0;i<10000;i++){
            if((i%50)==0){
                lst.remove(i);
            }           
        }
        System.out.println(lst.size());

    }

しかし、このコードを実行すると例外が発生します

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 9850, Size: 9803
    at java.util.ArrayList.rangeCheck(ArrayList.java:604)
    at java.util.ArrayList.remove(ArrayList.java:445)
    at com.ilex.reports.action.rpt.CNSReports.main(CNSReports.java:301)

もう1つ注意すべきことは ここに画像の説明を入力

次に、コードを1つ変更しました。つまり、2番目のループを5000まで繰り返し、正常に機能しました

ここに画像の説明を入力

質問は、 なぜ IndexOutOfBoundsException を与えるのですか?

その modCoutn は何ですか?

はい、それを解決する方法がある場合、このことのいずれかがメモリリークの原因になりますか?

前もって感謝します。

4

6 に答える 6

16

リストから要素を削除すると、リストが小さくなります。2 番目のループは 10000 まで実行されますが、そこに到達するまでにリストは 10000 未満に縮小されます。

実際、意図が 50 の倍数をすべて削除することである場合、50 のステップ サイズで 10000 から 0 まで逆方向にループして、この問題を回避し、高速化することができます。

for (int i=9950; i>=0; i-=50){
    lst.remove(i);
}

最初に各インデックスの値がインデックスであるという不変条件を削除した後、保持されなくなるため、50 の倍数を削除することが意図されている場合、現在のアプローチは機能しないことに注意してください。

modCount は、ArrayList が Iterators を参照して変更されたかどうかを検出するために使用する内部変数です。基本的に、リストへのすべての変更をカウントします。Iterator は独自のカウントを保持し、List との同期が維持されているかどうかを確認します。

コードが原因でメモリ リークが発生していません。Java メモリでは、使用されなくなったオブジェクトがまだ参照されている場合に「リーク」が発生するため、ガベージ コレクションを実行できません。ただし、例のすべてがメソッドのスコープ外に渡されるため、メソッドを終了するとすべてを gc できます。(そしてこれがメインのメソッドであるため、vm は実行を停止し、メモリも解放します)

于 2012-12-11T06:10:19.430 に答える
3

リストは、配列によってArrayList裏打ちされていても、配列ではありません。

intArray[i] = null;

と同じではありません

arrayList.remove(i);

2 番目 ( を使用ArrayList) では、実際にはすべての要素i+1を上下にシフトしているため、リストのサイズが小さくなっています。

反復を行っているリストから要素を削除する必要がある場合は、次を使用できますIterator

Iterator<Integer> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    iterator.next(); // consume current item
    if ((i++ % 50) == 0) {
        iterator.remove();
    }
}

または、このハッキーハックを使用できます

for(int i=0, len=lst.size();i<len;i++){
    if((i%50)==0){
        lst.remove(i);
        len--;  // decrease size of upper bound check
    }           
}

// or better...
for (int len=lst.size() - 1, i=len - (len % 50); i>=0; i-=50){
   lst.remove(i);
}

...しかし、反復子の解決策はこの状況にどう立ち向かうべきか通常、 をステップ実行する方法Collection

は、あなたまたは( )内の要素のmodCountたびにインクリメントされます。これは重要です。なぜなら、要素を繰り返し処理しているときに、途中で要素を「見逃す」ことや、何か別の変更を加えたくないからです。(これは特にマルチスレッド アプリケーションに当てはまります。) したがって、反復子の使用中に何らかのプロセスが変更を加えると、反復子が作成されてからリストが変更されたという警告が表示されます。(List. iterator()を参照)addremoveListArrayListArrayListConcurrentModificationException

ArrayList最後に、最後の質問ですが、リストの要素が別の場所で参照されていない限り、メモリ リークや について心配する必要はありません。Java では、オブジェクトが他のオブジェクトから参照されなくなるとすぐに、ガベージ コレクションの候補になります。

于 2012-12-11T06:17:13.387 に答える
1

リスト内の要素を削除すると、リストのサイズが小さくなりました。

于 2012-12-11T06:12:56.503 に答える
1
 List<Integer> removeElements = new ArrayList<Integer>(); 
 for(int i=0;i<10000;i++){
            if((i%50)==0){
                removeElements.add(lst.get(i));
            }           
        }

 lst.removeAll(removeElements);

これはこれを行うより安全な方法です

メモリリークについて:

ここでは、メモリ リークについて心配する必要はありません。メモリ リークは、参照が必要以上に長くスタックし、ガベージ コレクションが取得されない場合に発生するためです。これは通常、静的参照が原因で発生します。

于 2012-12-11T06:14:40.793 に答える
1

あなたはおそらくこれをしたいと思うでしょう:

for(int i=0;i<10000;i++){
        if((i%50)==0){
            lst.remove(Integer.valueof(i));
        }           
    }

リストには、インデックスによる削除とオブジェクトによる削除の 2 つのメソッドがあります。リストには OBJECTS が含まれており、それにいくつかの「int i」(プリミティブ) を追加しますが、コンパイラはそれをオートボクシングに置き換えます。

Integer.valueof(i)

したがって、削除するときは、オブジェクトではなくインデックスで削除します。

たとえば、次のリストがあります: {3, 2, 1}

電話すると:

  • remove(0), リストは次のようになりました: {2, 1} // ID で削除
  • remove(1), リストは次のようになりました: {3, 1} // ID で削除
  • remove(Integer.valueof(1)), リストは次のようになりました: {3, 2} // オブジェクトごとに削除
于 2012-12-11T06:15:50.953 に答える
0

1番目のポイント:コードのこの部分では、リストの要素を削除しています。以下を参照してください。

for(int i=0;i<10000;i++){
            if((i%50)==0){
                lst.remove(i);
            }           
        }

これが、リストサイズが小さくなり、そのエラーが発生する理由です。java.lang.IndexOutOfBoundsException

2番目のポイント:modCountは、リストの日食の内部カウントのように見えます。3番目のポイント:リストサイズが小さくなっているため、これはメモリリークの理由にはなりません。

これがお役に立てば幸いです。

于 2012-12-20T17:28:10.143 に答える