[Java]デフォルトコンストラクタとかコピーコンストラクターとか

わかりやすいJava_オブジェクト指向編を読んで勉強中。。Javaのコンストラクターのメモ。phpと比較しつつメモメモ

コンストラクタとデフォルトコンストラクター

public class Konsutorakuta {
  public static void main(String[] args) {
    // new Konsutorakuta; phpでは通るけどコンパイルエラー
    new Konsutorakuta();
  }
}
public class Konsutorakuta {
  public static void main(String[] args) {
    new Konsutorakuta(); // コンパイルエラー
  }
  public Konsutorakuta(int x){}
}
public class Konsutorakuta {

  public static void main(String[] args) {
    new Konsutorakuta(1);
  }

  public Konsutorakuta(int n) {
    this(true);
    System.out.println(n);
  }

  protected Konsutorakuta(boolean b) {
    this("文字列");
    System.out.println(b);
  }

  private Konsutorakuta(String s) {
    System.out.println(s);
  }

}

結果

文字列
true
1
public class Konsutorakuta {

  public static void main(String[] args) {
    new Konsutorakuta(666);
  }

  Konsutorakuta(){}

  Konsutorakuta(int n) {
    System.out.println(n);
    this(); // コンパイルエラー
  }

}
  • コンストラクタは継承されない
  • コンストラクタはメソッドではない
  • コンストラクタを定義しなかった場合は、コンパイラによりデフォルトコンストラクターが定義される
  • コンストラクタに返り値はない。だから返り値の型を指定しない。返り値の型を指定(void を含む)した場合は普通のインスタンスメソッドになるだけ。
  • コンストラクターを定義した場合は、デフォルトコンストラクターは定義されない。
  • コンストラクター中で this() によりコンストラクターを呼び出せる。this() という書き方はコンストラクタ内でのみ使える
  • 当たり前のことだけど コンストラクタに static は付けられない
  • コンストラクターの呼び出しは、コンストラクター内の最初のステートメントでなければならない。ただしフィールド
  • コンストラクターも他のメソッド同様オーバーロードできる

コピーコンストラクタ

同じクラスのインスタンスを受け取りそのフィールドの値を新しいインスタンスにコピーするコンストラクタをコピーコンストラクタと呼ぶ。インスタンスのディープコピーに使う。

public class CopyConstracter {
  private int field;

  public static void main(String[] args) {
    CopyConstracter a = new CopyConstracter(333);
    a.field += 444;
    CopyConstracter b = new CopyConstracter(a);
    System.out.println(b.field);
  }

  public CopyConstracter(int f1) {
    this.field = f1;
  }

  public CopyConstracter(CopyConstracter obj) {
    this.field = obj.field;
  }
}

結果

777

スーパークラスのコンストラクタ

public class SuperConstructorTest {
  public static void main(String[] args) {
    Child obj;
    obj = new Child();
    obj = new Child("子供");
  }

}

class Ancestor {
  Ancestor() {
    System.out.println("Ancestor();");
  }

  Ancestor(String s) {
    System.out.println("Ancestor says : " + s);
  }

  Ancestor(String... s) {
    this("Ancestor's constractor id called");
    for (String v : s)
      System.out.print(v + " ");
    System.out.println();
  }
}

class Parent extends Ancestor {
  Parent() {
    super("Parent's", "constructor", "calls", "super-constructor");
    System.out.println("Parent();");
  }

  Parent(String s) {
    System.out.println("Parent says : " + s);
  }

  void Ancestor(String s) {
  }
}

class Child extends Parent {
  Child() {
    System.out.println("Child();\n");
  }

  Child(String s) {
    super("Child calls Me.");
    System.out.print("Child says : " + s);
  }
}

結果

Ancestor says : Ancestor's constractor id called
Parent's constructor calls super-constructor
Parent();
Child();

Ancestor();
Parent says : Child calls Me.
Child says : 子供
  • スーパークラスのコンストラクタが先にコールされる。phpにはこのルールが存在しない。
  • phpでは継承したクラスのコンストラクタは呼ぶ必要がないし、 呼びたい場合はサブクラスのコンストラクタ内からスーパークラスのコンストラクタをコールする必要があった。でもJavaではスーパー・コンストラクタが実行されなければコンパイルエラーとなる。
  • スーパーコンストラクタを明示的に指定する場合は super(arg) を使用する
  • 明示的にコンストラクタをコールしていない場合、Javaのスーパーコンストラクタは引数の無いものが自動的にコールされる。つまり super(); は省略可能ということ、省略した場合は super() がコールされるということ。
  • コンストラクターは通常のメソッドの名前空間を汚染しない。
  • 1つのコンストラクター内に this() と super() を2つ記述することはできない。おかしなことになるしね。。

コンストラクタと可視性

public class Child extends Parent {
  public static void main(String[] args) {
    new Child();
  }

  Child() {}
}

class Parent {
  public Parent() {
    this(777);
  }

  private Parent(int n) {
    System.out.println(n);
  }
}

結果

777
  • 可視性の指定も可能で、スーパークラスのコンストラクターが private だった場合はサブクラスから直接コールできない。
  • privateコンストラクタしかないクラスはインスタンスを生成できない。 だからこれを利用してインスタンスを生成できないクラスを作ることができる。ただコンストラクタをprivateにすると絶対にインスタンスを生成できないというわけではなくそのオブジェクト内のメソッドで生成することが可能ではあるので完全にインスタンスの生成を防ぐためにはそのオブジェクト内にそのオブジェクトのインスタンスを返すようなスタティックメソッドを入れてはダメ。まぁこんなことしないだろうけど…

    package jp.fernweh;
    
    public class P {
    private P() {
    // プライベートなコンストラクタ
    }
    public Hoge() {
    new P();
    }
    }
    
    // 以下別パッケージ
    package net.fernwelt;
    
    import jp.fernweh.P;
    
    public class Test {
    
    public static void main(String[] args) {
    P p = new P(); // コンパイルエラー
    }
    
    }
Share
関連記事