6

この Java コードを指定すると、これは0 と 4 を出力します。

class A{
   A() {  print();   }
   void print() { System.out.println("A"); }
}

class B extends A{
   int i =   Math.round(3.5f); 

   public static void main(String[] args){
      A a = new B();
      a.print();
   }
   void print() { System.out.println(i); }
}

そして、この同一の C# コードでは、これは4 と 4 を出力します

システムを使用する;

class A{
   internal A() {  print();   }
   virtual internal void print() { Console.WriteLine("A"); }
}

class B : A{
   int i =  (int) Math.Round(3.5f); 

   public static void Main(string[] args){
      A a = new B();
      a.print();
   }
   override internal void print() { Console.WriteLine(i); }
}

Java では出力が 4 と 4 になるはずですが、実際の答えは Java では 0 と 4 です。それから私はC#でそれを試しました、答えは4と4です

何を与える?Java の理論的根拠は、B の構築中、A はまだ初期化中です (したがって、Java が A がまだ初期化中であると言った場合、B はまだ初期化中であると仮定します)。そのため、デフォルト値は 0 である必要があります。したがって、出力は Java では 0 と 4 です。

C# コンストラクターの動作が Java と異なる、またはその逆の理由は?

4

2 に答える 2

8

これは、コンストラクターでのオブジェクトの初期化の順序が異なるために発生しています。

Java で何が起こっているか:

  • (空、暗黙) B のコンストラクターが呼び出される
  • A のスーパークラス コンストラクターが呼び出されます (i が初期化されていないため、0 が出力されます)。
  • i はスーパークラス コンストラクターの後で初期化されます
  • print() が呼び出されます (プリント 4)

C# で何が起こっているか:

  • (空、暗黙) B のコンストラクターが呼び出される
  • i はスーパークラス コンストラクターを呼び出す前に初期化されます
  • A のスーパークラス コンストラクターが呼び出されます (i は既に初期化されているため、4 が出力されます)。
  • print() が呼び出されます (プリント 4)

どちらが正しいとか間違っているというわけではありません。これは、コンパイラが構築操作を順序付ける方法の違いにすぎません。個人的には、サブクラスの初期化が行われる前にスーパークラスが完全に構築されていることが理にかなっているからです。

いずれにせよ、ロジックが非常に複雑になる可能性があるため、一般に、オブジェクトの構築中に仮想メソッドを呼び出すことは避けることをお勧めします。

于 2012-05-16T04:11:59.780 に答える
1

Java での初期化の順序:

1.インスタンスのストレージはゼロに消去され、オブジェクト内のすべてのプリミティブが自動的にデフォルト値 (数値の場合はゼロ、ブール値と文字の場合は同等) に設定され、null への参照が設定されます。

2.ベースのコンストラクタをclass A呼び出します。オーバーライドされたprintメソッドであるため、 のメソッドを呼び出します。は現時点で 0 です。class Bi

3.クラスBのメンバ初期化を行います。今iも4です。

この種の驚きを引き起こさないようにするために、非静的または非プライベート メソッドをコンストラクターで呼び出さないでください。これらのメソッドは派生クラスでオーバーライドされる可能性があるためです。

于 2012-05-16T06:09:19.457 に答える