はじめに
こんにちは。
スッキリわかるJava入門に続いて、スッキリわかるJava入門 実践編の学習を進めています。
この学習記録を備忘録として残しながら、自身の理解を深めたいと思っています。
実践編では、4部構成で下記のようになっています。
・第1部「さまざまな基本機能」
・第2部「外部資源へのアクセス」
・第3部「効率的な開発の実現」
・第4部「より高度な設計をめざして」
今回は第1部 / 1章「インスタンスの基本操作」について学びました。
toString()、equals()、hashCode()、compareTo()、clone() といったメソッドを正しく実装することで、Javaのライブラリと自然に連携するクラスが設計できます。
この記事が、同じくJavaの学習をしている人にとっても参考になりましたら幸いです。
参考書籍について
- 書籍名:スッキリわかるJava入門 実践編
- 著者:中山清喬
- 出版社:インプレス
目次
1. 本章の要点
インスタンスの5大基本操作
1. toString()
インスタンスの内容を人が読みやすい文字列で表現します。System.out.println()で使われることが多いです。
public class Hero {
private String name;
private int hp;
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
@Override
public String toString() {
return this.name + " (HP:" + this.hp + ")";
}
}
public class Main {
public static void main(String[] args) {
Hero hero = new Hero("ミナト", 100);
System.out.println(hero); // 出力:ミナト (HP:100)
}
}
2. equals()
2つのインスタンスが「同じ内容」かを判定します。メモリアドレスではなく、値で比較します(等価判定)。
等値と等価の違い
等値:2つの変数が同じメモリアドレスを指している(参照が同じ)
等価:2つのインスタンスの内容が同じ(値が同じ)
public class Hero {
private String name;
private int hp;
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Hero)) {
return false;
}
Hero other = (Hero) obj;
return this.name.equals(other.name) && this.hp == other.hp;
}
}
public class Main {
public static void main(String[] args) {
Hero hero1 = new Hero("ミナト", 100);
Hero hero2 = new Hero("ミナト", 100);
Hero hero3 = new Hero("アサカ", 80);
System.out.println(hero1.equals(hero2)); // 出力:true
System.out.println(hero1.equals(hero3)); // 出力:false
}
}
3. hashCode()
インスタンスを識別するためのハッシュコード(整数値)を返します。HashMapなどのコレクションで使われます。
public class Hero {
private String name;
private int hp;
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
@Override
public int hashCode() {
return Objects.hash(this.name, this.hp);
}
}
public class Main {
public static void main(String[] args) {
Hero hero = new Hero("ミナト", 100);
System.out.println(hero.hashCode()); // 出力:ハッシュコード(整数)
}
}
4. compareTo()
2つのインスタンスの大小関係を定義します。この方法を実装することで、
Collections.sort()などでインスタンスのリストを自動的に並べ替えられます。
import java.util.*;
public class Hero implements Comparable<Hero> {
private String name;
private int hp;
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
@Override
public int compareTo(Hero other) {
return this.hp - other.hp; // HPが低い順にソート
}
@Override
public String toString() {
return this.name + " (HP:" + this.hp + ")";
}
}
public class Main {
public static void main(String[] args) {
List<Hero> heroes = new ArrayList<>();
heroes.add(new Hero("ミナト", 100));
heroes.add(new Hero("アサカ", 80));
heroes.add(new Hero("シェナ", 120));
System.out.println("ソート前:");
for (Hero hero : heroes) {
System.out.println(hero);
}
// compareToでソート
Collections.sort(heroes);
System.out.println("HPでソート:");
for (Hero hero : heroes) {
System.out.println(hero);
}
// 出力:
// アサカ (HP:80)
// ミナト (HP:100)
// シェナ (HP:120)
}
}
5. clone()
インスタンスの複製を作成します。元のインスタンスに影響を与えず独立したコピーを得られます。
public class Hero implements Cloneable {
private String name;
private int hp;
public Hero() {
}
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
@Override
public Hero clone() {
Hero result = new Hero();
result.name = this.name;
result.hp = this.hp;
return result;
}
public void setHp(int hp) {
this.hp = hp;
}
@Override
public String toString() {
return this.name + " (HP:" + this.hp + ")";
}
}
public class Main {
public static void main(String[] args) {
Hero hero1 = new Hero("ミナト", 100);
Hero hero2 = hero1.clone();
hero2.setHp(50);
System.out.println(hero1); // 出力:ミナト (HP:100)
System.out.println(hero2); // 出力:ミナト (HP:50)
}
}
5つのメソッドをオーバーライドする理由
-
toString():デフォルトではクラス名@ハッシュコードという意味不明な文字列になるため、人が理解できる表現にする必要がある。
-
equals():デフォルトでは参照比較(メモリアドレス比較)のみなので、内容比較(等価判定)を実装する必要がある。
-
hashCode():HashMapやHashSetで正確に動作させるため、equalsの結果と一貫したハッシュコードを返す必要がある。
-
compareTo():ソート時に意図した順序にするため、大小関係を定義する必要がある。
-
clone():正確な複製を保証するため、独立した複製を作成する必要がある。
2. 自分なりの解釈
- これらのメソッドを正しく実装することで、インスタンスの操作がより安全で効率的になります。
- そして自作クラスがHashMapやTreeSetなどのJavaライブラリと自然に連携できるようになることがわかりました。
- インスタンスの「見える化」「比較」「識別」「並べ替え」「複製」という
各々の操作が異なるメソッドで実現されていることの重要性が分かりました。
最後まで見ていただきありがとうございました。
次回は、第1部 / 2章「さまざまな種類のクラス」について書く予定です。