javaにおける相続関係クラスのロード順序の問題を詳しく説明する。


javaにおける相続関係クラスのロード順序の問題を詳しく説明する。
インスタンスコード:

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  public SonClass(){
    System.out.println("SonClass's constructor");
  }
  { System.out.println("SonClass's block");}
  static {
    System.out.println("SonClass's static block ");
  }

  public static void main(String[] args) {
    System.out.println("------ main start ------ ");
    new SonClass();
    System.out.println("------ main end ------ ");
  }
}

class ParentClass{
  public ParentClass(){
    System.out.println("ParentClass's constructor");
  }
  { System.out.println("ParentClass's block");}
  static {
    System.out.println("ParentClass's static block ");
  }
}

実行結果:

ParentClass's static block 
SonClass's static block 
------ main start ------ 
ParentClass's block
ParentClass's constructor
SonClass's block
SonClass's constructor
------ main end ------ 
運行結果により、一目瞭然です。mainメソッドでnew SonClass()を実行する前に、クラスローディング後にクラスのstaticコードブロックを実行しました。その後、メインメソッドに進んで、new操作を行うと、当然ながら、newサブクラスの操作を行う際には、親の構造コードブロック(コードの中では大きな括弧のみで包まれたコード)と構造関数を先に実行して、サブクラスの構造コードブロックと構造関数を実行します。
コードを修正して、運行の結果を見てみます。

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  ParentClass parentClass;
  public SonClass(){
    System.out.println("1");
  }
  public SonClass(String name){
    System.out.println("2");
    this.name = name;
    parentClass = new ParentClass("FEI");
  }

  public static void main(String[] args) {
    System.out.println("------ main start ------ ");
    new SonClass("fei");
    System.out.println("------ main end ------ ");
  }
}

class ParentClass{
  String name ;
  public ParentClass(){
    System.out.println("3");
  }
  public ParentClass(String name){
    System.out.println("4");
    this.name = name ;
  }
}

運転の順序は:

------ main start ------ 
3
2
4
------ main end ------ 
最初のルール:サブクラスの構造過程では、親の構造方法を呼び出さなければなりません。一つのクラスでは、構造方法を書かないとコンパイラがデフォルトの構造方法(つまりパラメータのない構造方法)を加えてくれますが、自分で構造方法を書いたらコンパイラが追加されなくなりますので、newのサブクラスのオブジェクトの場合は、必ずサブクラスの構造方法を呼び出します。しかし、サブ構造法において、super()のような基本的な構造方法を呼び出して表示されていない場合。このように親類のパラメータがない構造方法を呼び出します。
第二のルール:サブクラスの構造方法には表示されていないベース構造の呼び出し方法がありますが、ベースクラスには無参の構造方法がないとコンパイルエラーが発生します。したがって、通常は表示が必要です。super(パラメータリスト)は、パラメータの構造関数を呼び出します。このとき無参の構造関数は呼び出されません。
要するに、サブクラスは父親の構造関数を呼び出していません。サブクラスの構造関数がパラメータを持っているかどうかに関わらず、デフォルトでは父親の無参の構造関数を呼び出します。親がいないとコンパイルエラーが発生します。
まだ二つの種類です。もうちょっと変えます。

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  private String name = "SonClass";

  public SonClass() {
    printName();
  }
  public void printName() {
    System.out.println("SonClass print name: " + name);
  }
  public static void main(String[] args){
    new SonClass();
  }
}

class ParentClass{
  private String name = "ParentClass";

  public ParentClass() {
    //System.out.println(this.getClass());
    printName();
  }
  public void printName() {
    System.out.println("ParentClass print name: " + name);
  }
}

上の二つの例を見たら、最後の例は迷いやすいです。運行結果は似ていると思う人がいるかもしれません。

ParentClass print name: ParentClass 
SonClass print name: SonClass
または:

ParentClass print name: SonClass
SonClass print name: SonClass
しかし、本当の結果はこうです。

SonClass print name: null
SonClass print name: SonClass
なぜかというと、コードの中の父のようなコンストラクタの中のこの注釈を開けば、分かりやすいです。System.out.printel(this.get Class()
結果は:

class SonClass
そうです。父のクラスのthis引用はサブクラスのインスタンスオブジェクトです。だから父の構造関数で呼び出されたのですか?それともサブクラスのprintName()の方法ですか?具体的な原因は私も十分に確認できます。個人的には、父のような構造方法を使っていますが、父のような具体的な対象を具体的に扱っていません。だから、thisはまだサブタイプの引用を指しています。
読んでくれてありがとうございます。みなさんのご協力をお願いします。ありがとうございます。