見出し画像

【Javaお勉強日記】リストとセットとマップの取り扱い方を勉強する

ArrayListって配列でしょって思っていたわたしへ。

ちがいます。

わたしより。

リストとセットとマップと配列

「配列」が、ごく一般的な配列。

int[] a = new int[5];
a[0] = 10;
a[1] = 11;
...
System.out.println(a[0]); // 10

みたいに使うやつ。先に型と要素数を決めておかないといけない、VBAの配列に近い感じ。ただし、要素数の再定義は出来ない

要素数の再定義出来ないと、不便!!

というときに登場するのが、可変長であるリスト

リストは、配列のように同じ要素を重複して格納できて、格納順も保存される。で、要素を追加すると自動的に拡張してくれる。

ただし「List」自体はインターフェイスなので、Listそのもののインスタンスを作ることはできない。そこで、Listインターフェイスを実装した、ArrayListクラスを使う。

ArrayList<String> testList;

で宣言する。このとき必ず、<>を使って値の型を宣言する必要があるので注意。(指定しなくてもエラーにはならないけど、古い仕様なので必ず宣言する習慣を付ける)あと、java.util.Listのインポートが必要。

他に、

要素の重複が出来ないSet
キーと値をペアで格納できるMap

がある。これらもインターフェイスで、使えるクラスはそれぞれ

HashSet→要素が重複出来ない・要素の並び順が不定
HashMap→キーと値のペアで格納できるが、並び順は不定

SetとMapはHashが基本でListだけArrayなのがわかりにくいけど、覚える。

さらにオプションで、格納順が保存されるLinkedシリーズ

LinkedList→要素の挿入・削除の効率のいいList実装クラス
LinkdHashSet→重複不可だが、格納順が保存される
LinkdHashMap→格納した順番で取り出せるMap

並べ替えに便利なTreeシリーズ

TreeMap→キーでソートした状態で取り出せるMap
TreeSet→重複不可で、ソートした状態で取り出せる

がある。

それぞれ、List同士、Set同士、Map同士なら同じインターフェイスを実装しているので、

List<String> listTest = new ArrayList<>();

みたいに、インターフェイス型でインスタンスを作っておくと、後々の取り回しが楽。

ちなみに、 new ArrayList<>(); の <>部分は、本来型指定をするんだけど、そこはコンパイラが自動でやってくれるから空欄で大丈夫。

自作クラスのオブジェクトをリストに追加したい

自作クラスのオブジェクトもリストに追加出来る。

例えば、Memberクラスを作っておいて、

List<Member> memberList = new ArrayList<>();

ってするだけでMember型のListを作ることが出来る。

んだけど、このままだと比較とか同一性の確認が出来ないので、List、Set、Mapに格納したいオブジェクトは equals() と  hashCode() をオーバーライドしないといけない。(ただ複数のオブジェクトをまとめて格納したいだけなら、オーバーライドしなくても動くには動く)

オーバーライドの方法はこんな感じ

public class Member {
    private int id;
    private String name;
   
    // コンストラクタとgetter略
    @Override
    public int hashCode(){
        // 一意になる値を返す
        return this.id;
    }
    
    @Override
    public boolean equals(Object obj){
       if(this == obj){
           // this == obj で、それぞれに入っている参照先を比べられる。
           // 参照先が同一なら同一のインスタンスなので同一オブジェクト。
           return true;
       }
       
       if(obj == null){
           // 渡されたobjがnullだったら同一であるはずがないのでfalse。
           return false;
       }
       
       if(this.getClass() != obj.getClass()){
           // 違うクラスのインスタンスだったら同じであるはずがないのでfalse。
           return false;
       }
       
       // 同じクラスのインスタンスなのは確認済みなので、自クラスにキャストできる
       Member other = (Member) obj;
       
       // 「この値が同じなら同じものとして扱う」フィールドを比較する
       // 例えばここでは個人ID
       if(this.id != other.getId()){
           // 違ったらfalse
           return false;
       }
       // ここまで全てをくぐり抜けてきたらtrue。
       return true;
    }
}

hashCode()はオブジェクトごとに一意になる値を返せばいい。自動生成とかで作ると、素数の倍数作ってこねくり回したりするけど、一意になるint値持ってるならそれを返せば良い。

あと、ソート機能を使いたい場合、Comparableインターフェイスを実装して、compareTo()メソッドをオーバーライドする必要がある。必要になったらやり方調べる。

ArrayListを宣言して値を追加して取り出す流れ


List<Member> memberList = new ArrayList<>();
Member member1 = new Member(1, "田中太郎");
memberList.add(member1);
System.out.println(memberList.get(0).getId());

インスタンスを作る際の、 new ArrayList<>(); のカッコの順番と、値にアクセスしたい時に、list[n]じゃなくてlist.get(n)で取る事に気をつければ、後はそんなに難しくない。

Setもadd()で要素を追加できる。
Mapの場合は、addじゃなくてput(key,val)を使う。


この記事が気に入ったらサポートをしてみませんか?