13コレクションオペレーションの最適化をマスターしなければならないJavaプログラマ

まず、Javaのコレクションインターフェイスの数を導入し、これらのインタフェースの実装クラスは、などのLinkedList、ArrayListに、ベクトル、スタック、HashtableのHashMapの、のWeakHashMapを含め、詳細に記載され、その後、いくつかの種類の経験の実装と使用に達成されるであろうWeakHashMapに焦点を当てながら、説明しています。私は読者がコレクションの操作、注意事項のモードのいくつかの理解を持つことができ、この論文で説明願っています。

実際のプロジェクト開発ではプログラムの衝撃性能とメンテナンス性の重要な一部となって、効率的かつ簡単にオブジェクトを管理する方法を、多くのオブジェクトが存在します。Javaは、このような問題を解決するためのフレームワークのコレクションを提供リニアテーブル、リンクリスト、ハッシュテーブルは、Java開発時間を作り、共通のデータ構造であり、JDKは、基本的なデータ構造を実装するために、対応する一連のクラスを提供してくれました、すべてのクラスはリスト1の関係のコレクションクラスを記述し、java.utilのこのパッケージに含まれています。

コレクションとの関係

Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

この記事では、コレクションフレームワークの概要の経験について話している、すべての紙ベースのコードJDK7ことに注意してください。

Ⅰ。コレクションインタフェース

コレクションインタフェース

コレクションは、インターフェイスの最も基本的なセットで、コレクションは、オブジェクトのグループ、すなわちコレクションエレメント(要素)を表します。コレクションは、同じ数の要素を可能に支持要素がソートされ、他のものではありません。JDKは直接、そのようなリストや設定などのサブインタフェースのコレクションから継承されているJDKクラスによって提供されるクラスのコレクションから継承されていません。すべてのクラス、Collectionインタフェースは、2つの標準コンストラクタを提供する必要があり、引数なしのコンストラクタは、空のコレクションを作成するために使用され、コレクションは新しいコレクションを作成するためのコンストラクタのパラメータを持っているこの新しいコレクションとマスを実装同じ要素のコレクションは、コピーコンストラクタの後にユーザーコレクションすることができます。

コレクションの各要素をトラバースするには?

かかわらず、イテレータを返すイテレータ()メソッドをサポートする実際の型コレクションは、反復子は、各コレクションの各要素への訪問を使用する方法の。次のように典型的な使い方は以下のとおりです。

Iterator it = collection.iterator();
// 获得一个迭代子
while(it.hasNext()){
    Object obj = it.next();
    // 得到下一个元素
}

コレクションインタフェースは、2つのインターフェイスを派生一覧と設定されています。

Collectionインタフェースの主な方法が用意されています。

  1. ブールアドオン(オブジェクトo)コレクションにオブジェクトを追加します。
  2. 指定されたオブジェクトを削除するためのブール削除(オブジェクトo)
  3. int型のサイズは()セット内の要素の現在の数を返します。
  4. ブール(オブジェクトo)オブジェクトの指定されたセットがあるかどうかを見つけることが含まれています。
  5. ブールのisEmpty()は、セットが空であるか否かを判断します。
  6. イテレータイテレータ()はイテレータを返します。
  7. ブールのcontainsAll(コレクションC)セットCセットの要素があるかどうかを確認します。
  8. ブールのaddAll(コレクションc)のコレクションに追加されたすべての要素の集合C。
  9. コレクション内のすべての要素を削除します)(クリア失います。
  10. 空のremoveAll(コレクションc)は、コレクションからCとセットでいくつかの要素を削除しました。
  11. コレクションを削除する空のretainAll(コレクションc)は、コレクションから要素Cが含まれていません。

Listインタフェース

一覧は正確に各要素の挿入位置を制御するには、このインターフェイスを使用し、コレクションを命じています。ユーザーは、Javaの配列と類似しており、リスト内の要素にアクセスする(配列の添字と同様の位置、にリスト要素)インデックスを使用することができます。設定し、以下異なる述べたように、リストは同じ要素を可能にします。

必要なインターフェース()メソッドは、リストにコレクション・イテレータの添加はまた、反復子()メソッドは、反復子インタフェースを返す提供します。方法及び基準Iteratorインターフェイスに比べ、反復子の数より多くのアドオン()などは、あなたは、追加、削除、要素を設定し、前方または後方トラバース機能することができます。一般的なクラスは、Listインタフェースは、LinkedListの、ArrayListに、ベクトル、およびスタックらを持って実装しています。

主なインタフェースは、メソッドのリストを提供します。

  1. ボイド追加(int型のインデックス、オブジェクト要素)が指定された位置にオブジェクトを追加します。
  2. ブールのaddAll(int型のインデックス、コレクションC)Cが指定されたセット位置に要素を追加しています。
  3. オブジェクトのget(int index)指定された位置リストの要素を返します。
  4. INTのindexOf(物体O)要素出現の第一位置Oを返します。
  5. オブジェクトremoveint(int index)指定された位置にある要素を削除します。
  6. オブジェクトセット(int型のインデックス、オブジェクト要素)要素インデックスの素子置換位置によって素子、置換要素を返します。

地図インタフェース

いいえ後継地図Collectionインタフェースません。バリューマップのキーは、マップすることができ、各キー値、マッピングマップは、同じキーを含めることはできません提供します。Mapインタフェースは、コレクションのビューの3種類の提供、マップキーの内容は、グループ値のセットのグループ、またはキーと値のマッピングのセットとして設定してもよいです。

提供する主な方法の地図:

  1. ブール等しい(オブジェクトo)比較のため、
  2. ブール削除(オブジェクトo)オブジェクトを削除します。
  3. (Object key、Object value)の添加キー和値を置きます。

ランダム・インタフェース

ランダム・インターフェース自体は任意の方法を提供していない記号インターフェイスである、オブジェクトRandomAccessインタフェースを呼び出すことによって、すべてのタスクは、オブジェクトへの高速ランダムアクセスをサポートするために考えることができます。このインタフェースの主な目的は、リストの高速なランダムアクセスの実装をサポートすることができるものを識別することです。任意の配列ベースの実装をリストで、すべてのリストの認識に基づいて、RaodomAccessインタフェースを達成しています。唯一の配列はリストを横断する高速ランダムアクセス、およびニーズのリストへのランダムアクセスを行うことができますので。したがって、このインターフェースの利点は、あなたがListオブジェクトは、アプリケーションのパフォーマンスを向上させるために、異なるリストに異なるアクションを実行するためには、高速なランダムアクセスのために処理されているかどうかを知ることができるということです。

Ⅱ。コレクションの紹介

LinkedListのクラス

LinkedListのは、null要素を許可Listインタフェースを実装しています。さらに、追加のLinkedListのは、入手削除、挿入するか、データのLinkedListのようなオペレーティング頭や尾。これらの操作は、LinkedListのスタック(スタック)、キュー(待ち行列)または両端キュー(のDeque)として使用することもできます。複数のスレッドがリストにアクセスする場合、あなたは自分のアクセスの同期を実装する必要があり、つまり、それはスレッドの同期ではありません、何も同期LinkedListの方法がありませんのでご了承ください。一つの解決策は、同期リストを構築するとき、などの方法をリストを作成することです

List list = Collections.synchronizedList(new LinkedList(...));

ArrayListのクラス

ArrayListのは、可変サイズの配列を実現します。これは、Nullを含むすべての要素を、ことができます。ランタイムのサイズは、のisEmptyは、設定、取得等が一定であるが、コストの配分は、N個の要素を追加すると、O(N)時間を要する、方法一定の追加、他の方法は、時間を実行すると、直線的です。

各ArrayListのインスタンスは、メモリ素子のアレイのサイズのために、容量が連続的に添加すること、新しい要素として自動的容量(キャパシティ)を大きくすることができました。必要が多数の要素を挿入する場合、挿入は、挿入の効率を向上させる能力を高めるためにensureCapacity ArrayListのメソッドを呼び出すことができます。そして、LinkedListのは、ArrayListには、非同期スレッド(非同期化)です。

メインArrayListの方法が提供さ:

  1. ブールアドオン(オブジェクトo)リストの最後に、指定された要素。
  2. (int型のインデックス、オブジェクト要素)リストに追加された要素を指定された指定された位置を追加ブール。
  3. ブールのaddAll(コレクションc)は、リスト指定されたセットの最後に追加されます。
  4. ブールのaddAll(int型のインデックス、コレクションc)は、リスト内の位置を指定し、指定されたセットに加えます。
  5. ブールクリア()すべての要素のリストを削除します。
  6. ブールクローンは、()の例のリストのコピーを返します。
  7. ブールリスト要素を含むかどうかを決定する(オブジェクトO)を含みます。
  8. ブールensureCapacity(int型M)、リストは、m個の要素を収容することができ、必要であれば、リストの容量を増加させます。
  9. オブジェクトのget(int index)指定された位置にある要素のリストを返します。
    10.Intリスト内のindexOf(オブジェクトELEM)検索インデックス指定された要素。
  10. int型のサイズ()は、現在のリスト内の要素の数を返します。

Vectorクラス

ベクターはArrayListに非常に似ている、ベクターは、スレッドの同期の間の差です。ArrayListのイテレータが同じインタフェースであるが、イテレータが作成さのステータスを変更する別のスレッドベクトルによって使用されている場合、ベクターが、同期しているので(例えば、いくつかの追加または削除作成が、ベクトル反復子によって作成要素)、メソッドのイテレータはConcurrentModificationExceptionをスローしますときに呼び出して、例外をキャッチする必要があります。

Stackクラス

スタックは、LIFOスタックを実装し、ベクターから継承されました。5つの追加的なアプローチを提供し、スタックのベクトルをスタックとして使用することができます。プッシュと基本的な方法にポップ添加は、方法覗く要素は、スタック内の試験要素の位置が空であるか否かを検出するスタック空方法、検索方法スタックが得られます。スタックスタックが作成したばかりの空であることに注意してください。

設定されたカテゴリ

セットは、繰り返し要素のコレクション、すなわちが含まれていない、任意の2つの要素がe1とe2のe1.equals(E2)= falseです。ヌル要素に設定します。明らかに、セットのコンストラクタの制約は、着信コレクションのパラメータが重複した要素を含めることはできませんがあります。いくつかの問題が発生する可能性があり、変数の要素は、変更の自身の状態に設定した場合は、操作変数オブジェクト(可変オブジェクト)注意しなければならないことに注意してください。

ハッシュテーブルクラス

ハッシュテーブルは、Mapインタフェースを継承したキーと値のマッピングに基づいて、ハッシュテーブルを実装します。非空(null以外)の任意のオブジェクトは、キーまたは値として使用することができます。入れ(キー、値)を使用してデータを追加し、二つの基本的な営業費用が一定である、(キー)取得を使用してデータを抽出しました。

ハッシュテーブルは、初期容量のパフォーマンスと負荷率2つのパラメータで調整します。通常、デフォルトの負荷係数0.75は、より良い時間と空間のバランスを達成しました。負荷率がgetおよびputなどの操作に影響を与えるだろう、スペースを節約するが、対応する時間が増加します見つけるために増加しました。Hashtableの簡単な例では、これら3つの図1,2,3のHashtableを置く、彼らはキー「1」、「2」、「3」、リスト2に示すコードです。

二、ハッシュテーブルの例

Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));

我々は2のように、そのような番号を削除する必要がある場合は、対応するキー、リスト3に示すコードで除去することができます。

第三に、データがHastableから読み込まれます

Integer n = (Integer)numbers.get(“two”); 
System.out.println(“two =”+ n);

対応するハッシュ関数によって計算の位置を決定するキー値としてオブジェクトので、これをキーとして、任意のオブジェクトが実装しなければならないとハッシュコードは、メソッドに等しいです。ハッシュコードとは、ハッシュ関数によって定義されるように、2つのオブジェクト、すなわちobj1.equalsは(OBJ2)= trueの場合のように、そして、その後、同じ非常に注意しなければならないあなたは自己定義Keyクラスとして使用する場合、ルートクラスObjectから継承されたメソッドを等しいですそれらのハッシュコードが同じでなければならないが、2つのオブジェクトが異なる場合、同じハッシュコードの2つの異なるオブジェクト、競合として知られる現象、競合が動作時間オーバーヘッドハッシュテーブル増加につながる場合、それらは必ずしも異なるハッシュコードされていませんしたがって、定義されたハッシュコード()メソッドのように、ハッシュテーブルの動作をスピードアップすることができます。

同じオブジェクトが別のハッシュコードを持っている場合は、ハッシュテーブルの操作だけで書くのではなく、複製はequalsメソッドをしながら、この問題は、最善の方法とhashCodeを避けるために、予期しない結果(ヌルをGetメソッドを楽しみにしてを返す)しますそのうちの一つ。

HashMapのクラス

HashtableのHashMapのとHashMapのは、非同期スレッドであることを除いて、などが挙げられるが、許可ヌル、すなわちNULL値とヌルキー。しかし、ハッシュマップと考えコレクションイテレータ動作時間費用とのHashMapの容量に比例し、(値()メソッドは、コレクションを返します)。反復操作のパフォーマンスが非常に重要である場合にはそのため、初期容量が低すぎるか、負荷率パラメータ、高すぎる設定されているハッシュマップではありません。

WeakHashMapクラス

HashMapのは改善され、その実装キー「弱い参照」でのWeakHashMap、キーはもはや外部の、[キーを回復することができGCによって参照されている場合。

Ⅰ。コレクション実践

ArrayListに、ベクトルは、LinkedListのは、AbstractListを達成からであり、AbstractListは直接Listインタフェースを実装し、AbstarctCollectionから延びています。アレイの実現を使用してのArrayListとベクトル、ArrayListの任意のスレッド同期化方法を提供しないので、スレッドセーフではない、ベクトル方法は、スレッドの同期、スレッドセーフな実装のほとんどで行われます。円形の二重にリンクされたリストデータ構造を使用してLinkedListは、接続は一連のエントリによって行われる、一つのエントリは、常に3つの部分から構成され、要素、前駆体およびリアドライブのコンテンツエントリをエントリ。

容量のためにArrayListの需要が現在のアレイのサイズ、拡大の必要性を超えた場合。拡張プロセスは、アレイは、最終的にSystem.arraycopyの()メソッドを呼び出して、コピー操作の多くは、配列のコピーになります。リストの使用にLinkedListの構造は、容量の大きさを維持する必要はありませんが、各要素は、新しいEntryオブジェクトを作成する必要が増加し、頻繁にシステムコールでより譲渡され、パフォーマンスがいくつかを持っていますまだリソースの一定量を占めるに影響は、継続的に新しいオブジェクトを生成します。したがって、常に要素が増加の最後に配列の継続性、ので、唯一の拡張および配列複製スペースの不足だけの配列を生成します。

ArrayListのベースのアレイを実装され、アレイ素子は、アレイ内の任意の位置に挿入された場合にデータが挿入されると、すべての要素が必然的に、位置、および従って低い効率を再配置する必要性につながる、連続したメモリ空間であります尾。LinkedListの挿入データは、パフォーマンスの低下を引き起こすことはありません。

削除操作のArrayListのすべての有効な要素は、より前方に位置の要素を配列の再構築を行い、削除されるべきで、再編成のオーバーヘッド配列大きく、要素の位置は、より信頼性の高い、より少ないオーバーヘッドを除去します。LinkedListのデータは、便利な半リストの途中で除去する必要があります。

四、ArrayListのとLinkedListの使用コード

import java.util.ArrayList;
import java.util.LinkedList;
public class ArrayListandLinkedList {
    public static void main(String[] args){
        long start = System.currentTimeMillis();
        ArrayList list = new ArrayList();
        Object obj = new Object();
        for (int i=0;i<5000000;i++){
            list.add(obj);
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
        start = System.currentTimeMillis();
        LinkedList list1 = new LinkedList();
        Object obj1 = new Object();
        for (int i=0;i<5000000;i++){
            list1.add(obj1);
        }
        end = System.currentTimeMillis();
        System.out.println(end-start);
        start = System.currentTimeMillis();
        Object obj2 = new Object();
        for (int i=0;i<1000;i++){
            list.add(0,obj2);
        }
        end = System.currentTimeMillis();
        System.out.println(end-start);
        start = System.currentTimeMillis();
        Object obj3 = new Object();
        for (int i=0;i<1000;i++){
            list1.add(obj1);
        }
        end = System.currentTimeMillis();
        System.out.println(end-start);
        start = System.currentTimeMillis();
        list.remove(0);
        end = System.currentTimeMillis();
        System.out.println(end-start);
        start = System.currentTimeMillis();
        list1.remove(250000);
        end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

6.3.5動作出力

639
1296
6969
0
0
15

HashMapのは、ハッシュ値は、メモリ・アドレス、キーに対応するデータに直接アクセスするにマッピングされ、キーハッシュアルゴリズムを実行されます。ハッシュマップでは、基礎となるデータ構造を使用して配列、すなわち、いわゆるメモリアドレスアレイ添字です。HashMapのパフォーマンスは、次のことを確認する必要があります。

  • ハッシュアルゴリズムは、効率的でなければなりません。
  • メモリアドレス(配列インデックス)アルゴリズムのハッシュ値が高速です。
  • これは、メモリアドレス(配列インデックス)に対応する値から直接得ることができます。

HashMapのは、実際にリンクされたリストの配列です。それは)長い(ハッシュコードとしてリンクリストの実装機構のHashMapに基づいて、導入、および十分に達成するためのハッシュ()メソッドされた、競合を極力低減することができ、その後のHashMapの操作は、ランダムアクセスの配列とほぼ同等です操作、優れた性能を有します。しかしながら、ハッシュコードIF()またはハッシュ()メソッドの実装は、競合の多数は、実際にはHashMapのいくつかのリンクリスト操作は、この時点でのHashMap、パフォーマンスの低下にリストをトラバースすることと等価である分解された場合には、不良です。

機能的な欠点は、その出力が乱れHashMapを、トラバースするとき要素は、ハッシュマップに格納され、そのHashMapの障害です。あなたが入力要素の順序を維持したい場合のLinkedHashMap代わりに使用することができます。

LinkedHashMapはしばらくのHashMapに基づいて、高効率で、ハッシュマップから継承され、記憶素子のために内部リストを追加します。

HashMapのハッシュアルゴリズムは、プットの最も急速な()およびGet()操作で実行することができます。TreeMapのは、完全に異なるMap実装を提供します。機能的には、TreeMapのHashMapのは、それが要素を並べ替えることができることを意味しSortedMapインタフェースを実装し、機能よりも強力なを持っています。少しHashMapの下のTreeMapの性能。あなたは、開発中の要素をソートする必要がある場合は、HashMapのは、この機能を実現することはできません使用し、出力は、要素の順序で実行TreeMapの反復を使用します。LinkedHashMap要素がアクセスまたは順序に基づいて順序付けされた順序に設定されている、TreeMapのは、(コンパレータ又は比較によって決定される)の要素の固有の順序に基づいています。

LinkedHashMapは、要素またはアクセスの増加する順序に従って順序付けされ、TreeMapの主な要素に従ってソートされます。

VIは、TreeMapのは(TreeMapのソートを実装)は、ビジネスロジックを実装しているコードを使用してソートを示しています。

import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class Student implements Comparable<Student>{
    public String name;
    public int score;
    public Student(String name,int score){
        this.name = name;
        this.score = score;
    }
    @Override
    //告诉 TreeMap 如何排序
    public int compareTo(Student o) {
        // TODO Auto-generated method stub
        if(o.score<this.score){
            return 1;
        } else if(o.score>this.score){
            return -1;
        }
        return 0;
    }
    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append("name:");
        sb.append(name);
        sb.append(" ");
        sb.append("score:");
        sb.append(score);
        return sb.toString();
    }
    public static void main(String[] args){
        TreeMap map = new TreeMap();
        Student s1 = new Student("1",100);
        Student s2 = new Student("2",99);
        Student s3 = new Student("3",97);
        Student s4 = new Student("4",91);
        map.put(s1, new StudentDetailInfo(s1));
        map.put(s2, new StudentDetailInfo(s2));
        map.put(s3, new StudentDetailInfo(s3));
        map.put(s4, new StudentDetailInfo(s4));
        //打印分数位于 S4 和 S2 之间的人
        Map map1=((TreeMap)map).subMap(s4, s2);
        for (Iterator iterator=map1.keySet().iterator();iterator.hasNext();){
            Student key = (Student)iterator.next();
            System.out.println(key+"->"+map.get(key));
        }
        System.out.println("subMap end");
        //打印分数比 s1 低的人
        map1=((TreeMap)map).headMap(s1);
        for (Iterator iterator=map1.keySet().iterator();iterator.hasNext();){
            Student key = (Student)iterator.next();
            System.out.println(key+"->"+map.get(key));
        }
        System.out.println("subMap end");
        //打印分数比 s1 高的人
        map1=((TreeMap)map).tailMap(s1);
        for (Iterator iterator=map1.keySet().iterator();iterator.hasNext();){
            Student key = (Student)iterator.next();
            System.out.println(key+"->"+map.get(key));
        }
        System.out.println("subMap end");
    }
}
class StudentDetailInfo{
    Student s;
    public StudentDetailInfo(Student s){
        this.s = s;
    }
    @Override
    public String toString(){
        return s.name + "'s detail information";
    }
}

七、出力を実行します

name:4 score:91->4's detail information
name:3 score:97->3's detail information
subMap end
name:4 score:91->4's detail information
name:3 score:97->3's detail information
name:2 score:99->2's detail information
subMap end
name:1 score:100->1's detail information
subMap end

キーへの参照があるときのWeakHashMap機能は、独自に追加されるものですが、このキーには他の参照がない場合、地図は自動的に値を破棄します。8マップは、2つのオブジェクトを宣言コードリストに示すように、ハッシュマップは、マップ、ハッシュマップAを削除し、A、B点Nullに同時にA、B 2つの2オブジェクトに、一つのWeakHashMapでありますWeakHashMapには自動的にオフに回復されます。このような状況の出現は、オブジェクトAのために、そしてときにHashMapのWeakHashMapは自動的に破棄されますので、Aさんへのポインタを持っていないにもAの外に保存されたのWeakHashMapに加えて、ポイント後にヌルを削除して、ため、B目標のためにNULLを指すが、Bに存在HashMapのポインタ、およびながらBはそれほどのWeakHashMapオブジェクト残ります。

八、のWeakHashMapのサンプルコード

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
public class WeakHashMapTest {
    public static void main(String[] args) throws Exception {
        String a = new String("a");
        String b = new String("b");
        Map weakmap = new WeakHashMap();
        Map map = new HashMap();
        map.put(a, "aaa");
        map.put(b, "bbb");
        weakmap.put(a, "aaa");
        weakmap.put(b, "bbb");
        map.remove(a);
        a=null;
        b=null;
        System.gc();
        Iterator i = map.entrySet().iterator();
        while (i.hasNext()) {
            Map.Entry en = (Map.Entry)i.next();
            System.out.println("map:"+en.getKey()+":"+en.getValue());
        }
        Iterator j = weakmap.entrySet().iterator();
        while (j.hasNext()) {
            Map.Entry en = (Map.Entry)j.next();
            System.out.println("weakmap:"+en.getKey()+":"+en.getValue());
        }
    }
}

九、出力を実行します

map:b:bbb
weakmap:b:bbb

自動解除メモリの目的を達成するように、主のWeakHashMap内部expungeStaleEntriesを通じてこの機能は、未使用のエントリを削除します。基本的に限り、その内部のエントリを削除するように、この関数を呼び出しますのWeakHashMapコンテンツへのアクセスは、もは​​や外部参照であるとして。しかし、事前に生成されたのWeakHashMap場合、および前GCにとのWeakHashMapを訪問していなかった、それはメモリがまだリリースされることはありませんではないでしょうか?

十、WeakHashMapTest1

import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
public class WeakHashMapTest1 {
    public static void main(String[] args) throws Exception {
        List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
        for (int i = 0; i < 1000; i++) {
            WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
            d.put(new byte[1000][1000], new byte[1000][1000]);
            maps.add(d);
            System.gc();
            System.err.println(i);
        }
    }
}

Javaのデフォルトのメモリは、メモリエラーから放り出され、64Mであるため、JVMのコードは、リスト10に示す例の動作のパラメータを変更しません。

XI、実行出力

241
242
243
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at WeakHashMapTest1.main(WeakHashMapTest1.java:10)

確かに、WeakHashMapにこの時間は、自動的に私たちは、未使用のメモリを解放するためには役立ちません。リスト12に示すコードは、メモリの問題の外になりません。

十二、WeakHashMapTest2

import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
public class WeakHashMapTest2 {
    public static void main(String[] args) throws Exception {
        List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
        for (int i = 0; i < 1000; i++) {
            WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
            d.put(new byte[1000][1000], new byte[1000][1000]);
            maps.add(d);
            System.gc();
            System.err.println(i);
            for (int j = 0; j < i; j++) {
                System.err.println(j + " size" + maps.get(j).size());
            }
        }
    }
}

それは、このテストは通常​​の出力を実行することが判明した、メモリオーバーフローの問題が発生しなくなりました。

全体的に、あなたはそれが自動的に内部で使用されていないオブジェクトを解放することができますが、その内容にアクセス時に内部のオブジェクトを解放しません。何もしていないのWeakHashMap。

弱参照を達成するのWeakHashMap、そのエントリのため<K、V>弱い参照<K>から継承され、そして

WeakHashMap $エントリに<K、V>クラスの定義とコンストラクタ関数は、リスト13。

サーティーン、のWeakHashMapクラス定義

private static class Entry<K,V> extends WeakReference<K> 
implements Map.Entry<K,V>
 Entry(K key, V value, ReferenceQueue<K> 
queue,int hash, Entry<K,V> next) {
    super(key, queue);
    this.value = value;
    this.hash = hash;
    this.next = next;
}

それは、親クラスのコンストラクタステートメントであることに注意してください:「スーパーは(キー、キュー);」、渡されたキーは、キー値が直接this.valueで強い参照に関連付けられている、したがって、弱い参照です。依然として(値は強くのArrayListでマップ、マップ関連のエントリ、エントリと関連にリンクされている)の値を維持したままにSystem.gc()におけるバイトアレイキーに、回収しました。

ループのために毎回新しい新しいWeakHashMapには、PUT操作の後、GCはキーに弱い参照されますが、バイト配列を回収し、ReferenceQueueにイベント通知が、ReferenceQueueを対処するためのWeakHashMapをトリガするために適切な措置に従いませんでしたパッケージには、WeakHashMapをキーに残っ弱い参照したがって、当然の対応する値が存在します。

この値は、それは()maps.getは11(J).sizeリスト、リストおよびプログラム分析ショーの11の二つの例のリストには?10をクリア価値の回復をトリガし、次に何がそれをトリガーされたときでしょうか?サイズメソッドは、エントリトラバーサル(中Quene)、およびブランク値のエントリを回復するJVM用expungeStaleEntriesメソッドを呼び出して見ソースを表示WeakHashMapには、メモリを回復しました。だから、効果はキーをクリアした後GC、バリューアクセスのWeakHashMapがクリアされたときにキーがクリアされています。

WeakHashMapスレッドクラスが同期されていない、方法同期Collections.synchronizedMapのWeakHashMapを構築するために使用されてもよく、各キーオブジェクトは、間接的に弱いオブジェクト参照を示すものとして記憶されています。従って、外部又はマップ内のいずれかの後、唯一の弱参照は、マップ内のガベージコレクタにキーをクリアし、キーは自動的に削除されます。オブジェクトのWeakHashMapの値が通常の強参照によって保持されることに留意すべきです。そのためのケアは、それがドロップされた鍵を防ぐので、オブジェクトの値は、直接的または間接的に自分のキーの強参照ではないように注意する必要があります。強い、オブジェクトの値は、それ自体のWeakHashMapそれらの対応するキーを参照することにより間接的であってもよいこと、すなわち、値オブジェクトは、いくつかの他の強力なキー・オブジェクトを参照することができる、キーオブジェクトに関連付けられたオブジェクトの値が最初のターンを指しますキーオブジェクトの値。

この問題を処理する方法を挿入する前のように、WeakReferences値そのものでパッケージに、次のとおりです。m.put(キー、新しい弱い参照(値))、その後、ソリューションは、このようなすべての「コレクションビューを取得でコーティングしました方法は「、反復子は、フェイルファストれ、反復子が作成された後、マップが構造的に変更された場合、反復子自体の削除または追加メソッド以外、どのような方法変更の他の時間を反復子を返しますConcurrentModificationExceptionを投げます。したがって、同時変更の顔には、イテレータではなく、将来の不確定な時に任意の動作が発生する危険を回避するために、速やかにかつクリーンに失敗します。

私たちは、イテレータが失敗しないことを保証することはできません、一般的には、同期の同時変更があると、どんな保証が完全に決定することは不可能です。

概要

総合前述の説明と例のコードでは、我々はそれがなどのオペレーティング・スタック、キュー、に来るならば、あなたはリストの使用を検討すべきで知ることができます。すぐに、挿入要素および他の操作を削除する必要が、あなたはLinkedListのを使用する必要があります。あなたは要素への高速なランダムアクセスが必要な場合は、ArrayListのを使用する必要があります。プログラム、または唯一のシングルスレッド環境でのスレッドでアクセスした場合、非同期クラス、高効率化を検討してください。複数のスレッドが、クラスを動作させることができる場合、クラスは、同期させるために使用されるべきです。正しい複製およびhashCodeのKeyオブジェクトは、equalsメソッドとして、ハッシュテーブルの操作に特別な注意を払ってください。後でArrayListをLinkedListの、クライアントコードは変更する必要はありません交換する必要がある場合、これは抽象的思考のためのプログラムであるように、代わりというよりも、このようなArrayListのリターンリストとして実際の型のインタフェースに戻るようにしてください。

この記事では、唯一の共有アプリケーションレベルのためである、フォローアップ記事をソースコードレベルで特定の深さの外観の達成のためになり、特定のアルゴリズムを実装しますが、詳細な説明に基づいており、フォローアップする記事を必要としてください読者の注意。

- - 終わり - -

13コレクションオペレーションの最適化をマスターしなければならないJavaプログラマ

おすすめ

転載: blog.51cto.com/14409778/2420847