【Java】HashMap コンストラクタの仕様をテストしてみた。
java.utilパッケージ、CollectionクラスのHashMapの仕様を確かめるべく行ったテストを記します。
Java Docの記載によると、
“デフォルトの初期容量(16)とデフォルトの負荷係数(0.75)を持つ、空のHashMapを作成します。”
とありましたので、デフォルトコンストラクタを呼んだ際のマップの初期容量が16であることを期待値として、正しく結果を返すためのテストを行います。
初期容量を取得するために、StringBuilderクラスのCapacity()メソッドのようなものがあればと思いましたが、そのような仕組みはHashMapにはありませんでしたので方法を探るべく、
“HashMap capacity get”
のように検索キーワードを使って調べてみた結果、
以下の記事に同じようにHashMapの初期容量を検証するための方法が記載されていました。
記事引用元サイト:stackoverflow
https://stackoverflow.com/questions/23628001/how-to-know-get-the-capacity-of-hashmap
記事で行っているコードの内容はリフレクションという仕組みを使用して、HashMapクラス内で定義されているマッピングの容量を決めている(?)tableというフィールドを取得してそちらをObject型で扱い、lengthで長さを取り出すことでマップの初期容量を確認しているようです。
今回はそれを参考に以下のようにJUnitでテストケースを作成してみました。
public static class マップの初期状態 { //TODO コンストラクタのテスト @Test public void 空のマップの初期容量は16である() throws Exception { Map<Integer,String> map = new HashMap<Integer,String>(); Field tableField = HashMap.class.getDeclaredField("table"); tableField.setAccessible(true); Object[] table = (Object[]) tableField.get(map); assertThat(table.length,is(16)); } }
※クラスファイルの先頭でCollectionやHashMap,junit.testなど必要なパッケージをインポートする必要がある。
テストを実行すると
NullPointerExceptionの例外がスローされてしまいました。
先ほどのテストコードに戻り、要素を一つだけマッピングし再度テストを実行してみたいと思います。
(9行目)
public static class マップの初期状態 { //TODO コンストラクタのテスト @Test public void 空のマップの初期容量は16である() throws Exception { Map<Integer,String> map = new HashMap<Integer,String>(); Field tableField = HashMap.class.getDeclaredField("table"); tableField.setAccessible(true); //要素をマッピング map.put(0,"ZERO"); Object[] table = (Object[]) tableField.get(map); assertThat(table.length,is(16)); } }
例外がスローされることなくテストが成功した。
初期容量は16であることを期待値として返すことができました。
ですが、
要素をマッピングした状態がマップの初期状態として正しいかどうかの懸念が残ったので、
もう少し深堀をして、HashMapクラスの中身を覗いてみました。
Eclipse上で実装を開いてみる。
中身を見てみると、テストケースで参照したtableというフィールドについて書かれている項目が390行目で確認出来ました。
The table, initialized on first use, and resized as
* necessary. ~
※「tableは最初の仕様時に初期化される」 というようなニュアンスで読み解いた。
このことからHashMapは要素をマッピングして初めて初期容量を持つことが出来る。
というような解釈で、初期容量についての仕様をテストしました。
またJava Docにあるコンストラクタのもうひとつの説明“デフォルトの負荷係数(0.75)を持つ~”の部分はまた別の記事で記したいと思います。