13.

インスタンス化完全ガイド — new・コンストラクタ・ファクトリ

編集
この記事の要点
  • インスタンス化=クラスから実体 (オブジェクト) を生成すること
  • Java/PHP/C# は new ClassName(args) 記法。Python は ClassName(args) (new 不要)
  • 引数なしコンストラクタを明示しないと 暗黙のデフォルトコンストラクタが生成される (他のコンストラクタが 1 つでもあれば生成されない)
  • ファクトリメソッド: User.of(...) 等で名前付き生成。new より読みやすく、キャッシュ・サブクラス返却が可能
  • Singletonはコンストラクタを private にして new を防ぐ。DI コンテナでは new をフレームワークに任せる

インスタンス化とは

クラス (設計図) からオブジェクト (実体) を生成する操作。Java では new キーワードを使います。

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// インスタンス化
User u = new User("Taro", 25);
//          ↑ new キーワード + コンストラクタ呼び出し
//
// 内部的に:
//   1. ヒープにメモリ確保 (User 1 個分)
//   2. フィールドを既定値で初期化 (name=null, age=0)
//   3. コンストラクタを呼び出してフィールド設定
//   4. オブジェクトの参照を u に代入

言語別の書き方比較

言語インスタンス化備考
JavaUser u = new User("Taro");明示的な new
PHP$u = new User("Taro");Java と同じ
C#var u = new User("Taro");Java と同じ
Pythonu = User("Taro")new 不要 (関数呼び出しと同じ)
JavaScriptconst u = new User("Taro");ES6 class
Rubyu = User.new("Taro")クラスのクラスメソッド
Kotlinval u = User("Taro")new 不要
// PHP
class User {
    public function __construct(
        public string $name,
        public int $age = 0,
    ) {}
}
$u = new User("Taro", 25);
$u = new User(name: "Taro");        // 名前付き引数 (PHP 8+)
# Python
class User:
    def __init__(self, name, age=0):
        self.name = name
        self.age = age

u = User("Taro", 25)       # new 不要
u = User(name="Taro")      # 名前付き引数

引数なしコンストラクタの自動生成

// ① コンストラクタを書かない場合
public class A { }
// → コンパイラが暗黙で「引数なし public コンストラクタ」を生成
A a = new A();   // ✅ OK

// ② 1 つでもコンストラクタを書いた場合
public class B {
    public B(String s) { }
}
// → 暗黙のデフォルトコンストラクタは ★ 生成されない
B b = new B();         // ★ コンパイルエラー
B b = new B("hello");  // OK

// ③ 引数なしを保持したい場合は明示
public class C {
    public C() { }            // 明示する
    public C(String s) { }
}

引数渡しの注意 (値渡し / 参照渡し)

public class Box {
    public int value;
    public Box(int v) { this.value = v; }
}

void f(int n)   { n = 999; }            // 基本型は値のコピー
void g(Box b)   { b.value = 999; }      // 参照のコピー → 中身は変わる
void h(Box b)   { b = new Box(0); }     // 参照を別物に → 呼び出し側に影響なし

int x = 1;
f(x);
System.out.println(x);  // 1 (影響なし)

Box box = new Box(1);
g(box);
System.out.println(box.value);  // 999 (中身書き換え)

Box box2 = new Box(1);
h(box2);
System.out.println(box2.value); // 1 (参照差し替えは伝わらない)

ファクトリメソッドパターン

new の代わりに名前付き static メソッドで生成する設計:

public class User {
    private String name;
    private boolean isAdmin;

    private User(String name, boolean isAdmin) {
        this.name = name;
        this.isAdmin = isAdmin;
    }

    // ファクトリメソッド (意図が読み手に伝わる)
    public static User createGuest(String name) {
        return new User(name, false);
    }

    public static User createAdmin(String name) {
        return new User(name, true);
    }

    public static User fromEmail(String email) {
        return new User(email.split("@")[0], false);
    }
}

User u1 = User.createGuest("Taro");
User u2 = User.createAdmin("admin");
User u3 = User.fromEmail("taro@example.com");

ファクトリの利点:

  • 名前で意図を表現できる (new User(true) → 何の true?)
  • キャッシュを返せる (Integer.valueOf(1) は -128〜127 を共有)
  • サブクラスを返せる (戻り値型は抽象、実装は具象)
  • コンストラクタを private にすれば new を完全に隠せる

リフレクションでインスタンス化

// クラス名 (文字列) からインスタンス生成
Class<?> cls = Class.forName("com.example.User");

// Java 9+ 推奨: getDeclaredConstructor + newInstance
Object u = cls.getDeclaredConstructor(String.class, int.class)
              .newInstance("Taro", 25);

// 引数なしのコンストラクタなら
Object u2 = cls.getDeclaredConstructor().newInstance();

// 旧来 (Java 9 で deprecated)
// Object u3 = cls.newInstance();

// 用途: フレームワーク (Spring DI / JUnit / Jackson) の内部実装

Singleton: new を防ぐ

public class AppConfig {
    private static final AppConfig INSTANCE = new AppConfig();

    private AppConfig() { }   // ★ private → 外から new できない

    public static AppConfig getInstance() {
        return INSTANCE;
    }
}

// 利用
AppConfig cfg = AppConfig.getInstance();
// AppConfig cfg2 = new AppConfig();  // ★ コンパイルエラー

// Java 5+ では enum Singleton が推奨
public enum AppConfig {
    INSTANCE;
    public void load() { ... }
}
AppConfig.INSTANCE.load();

DI (依存性注入) でインスタンス生成をフレームワークに任せる

@Service
public class UserService {
    private final UserRepository repo;

    // ★ new ではなくフレームワークが自動注入
    public UserService(UserRepository repo) {
        this.repo = repo;
    }
}

// アプリ側は new しない
@Autowired
private UserService userService;

// DI の利点:
// - テスト時にモックを差し替えやすい
// - ライフサイクル管理を Spring が肩代わり
// - 設定で実装クラスを切替可能

FAQ

Q: new を忘れるとどうなる?
A: Java はコンパイルエラーになり気付ける。Python は普通の関数呼び出しと同じ書式なので「忘れる」概念がない。

Q: 引数なしコンストラクタが必要なケース
A: JPA / Hibernate / Jackson 等のフレームワークがリフレクションで生成するため、引数なし public コンストラクタが要求されることがある。

Q: final クラスでもインスタンス化できる?
A: できる。final class継承不可を意味するだけで、new は問題なく可能。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ