答群友問:Java静的内部クラス、一般内部クラスなどの理解

3693 ワード

昨日、あるグループの友达はあるグループの中で一つの問題を出しました.内容は以下の通りです.
public class Base {
	private String baseName = "base";
	public Base(){
		callName();
	}
	
	public void callName(){
		System.out.println(baseName);
	}

	 static class Sub extends Base{
		private String baseName = "sub";

		public void callName(){
			System.out.println(Sub.this.baseName);
		}
	}
	
	public static void main(String[] args){
		Base b = new Sub();
	}
}
以上のBaseクラスのmain()メソッドは、いったい出力内容は何ですか?
Subを構築するときにsuperの構築方法を呼び出す理由と、Baseの構築方法でcallName()メソッドを呼び出す理由があるので、出力は親のbaseName、すなわち内容はbaseであり、Subを構築するときにsuperの構築方法を呼び出すが、Baseの構築方法でcallName()メソッドを呼び出す理由がある.ただし、サブクラスSubは親ベースのcallName()メソッドを書き換えているので、サブクラスのbaseName、すなわちsubとして出力されます.
私の分析はnullであるべきです.なぜですか.この類を少し改造すると以下のようになります.
public class Base {

	static {
		System.out.println("  Base          !");
	}

	private String baseName = "base";

	public Base() {
		System.out.println("  Base         !");
		System.out.println("  Base     baseName     " + baseName);
		callName();
	}

	public void callName() {
		System.out.println("  Base callName()      !");
		System.out.println(baseName);
	}

	 static class Sub extends Base {
		
		static{
			System.out.println("  Sub          !");
		}
		
		public Sub(){
			System.out.println("  Sub         !");
		}
		
		private String baseName = "sub";

		public void callName() {
			System.out.println("  Sub callName()      !");
			System.out.println(baseName);
		}
	}

	public static void main(String[] args) {
		Base b = new Sub();
	}
}
Baseのmain()メソッドを実行すると、結果は何になりますか?答えは次のとおりです.
  Base          !
  Sub          !
  Base         !
  Base     baseName     base
  Sub callName()      !
null
  Sub         !
どうしてこんなことになったの?その概要を簡単に分析するには、次のようにします.
1、まず、Baseのmain()メソッドのBaseb=new Sub()を実行する.文の場合、Subクラスに遭遇すると、JVMはSubクラスを先にロードしますが、それをロードするとextendsキーワードに遭遇するので、Subクラスをロードする前に親ベースをロードし、最初の行から出力された「親ベースの静的コードブロックが呼び出されました!」ちょうどこの点を検証した.
2、次に、Subクラスをロードする番になったので、2行目の出力は「サブクラスSubの静的コードブロックが呼び出された!」である.
3、そして、クラスのロードが完了し、new操作が実行されました.周知のように、new操作はオブジェクトをインスタンス化していますが、サブクラスがインスタンス化されると、親クラスの構築方法が呼び出されるのではないでしょうか.答えは肯定的で、3行目の出力結果も確かに「親ベースの構造方法が呼び出された!」
4、親ベースの構築方法では、親ベースのメンバー変数baseNameの値を出力し、出力した値もbaseである.
5.次に、callName()メソッドを呼び出します.では、このcallName()は親クラスを呼び出すべきですか、それとも子クラスを呼び出すべきですか.初期化されたサブクラスなので、サブクラスもちょうど親のcallName()メソッドを書き換えたので、結果はサブクラスを呼び出すcallName()メソッドに違いないが、5行目の出力結果も確かに「サブクラスSubのcallName()メソッドが呼び出された!」6、サブクラスのcallName()メソッドを呼び出す以上、サブクラスのbaseNameの値を出力すべきで、subではないでしょうか.まず関所を売って、次の出力を見てください.
7、7行目の出力結果は「サブクラスSubの構築方法が呼び出された!」何を説明しましたか.サブクラスcallName()メソッドを呼び出すと、サブクラスSubがインスタンス化されていないため、メンバー変数baseNameの値は「sub」ではなくnullしかないので、振り返って6行目の結果nullが出力されるのも不思議ではありません.
特に、サブクラスのメンバー変数baseNameをstaticと定義すると、結果は異なり、subとして出力されます.Subコンストラクションメソッドの実行前にサブクラスのcallName()メソッドが呼び出されますが、サブクラスメンバー変数baseNameがstaticとして定義されているため、サブクラスがJVMにロードされるとbaseNameの初期化が実行されます.出力結果は次のとおりです.
  Base          !
  Sub          !
  Base         !
  Base     baseName     base
  Sub callName()      !
sub
  Sub         !

以上がその群友問題に対するすべての解答である.
次に、Javaの静的内部クラス、一般内部クラスなどの違いを簡単に振り返る:1、構造形式:静的内部クラスには2つの構造方式があり、1つ目は直接newの内部クラス名()であり、例えば上のBaseb=new Sub()であり、2つ目は外部クラスのクラス名に基づいている.内部クラス名()は、Baseb=new Baseのようなnew操作を行う.Sub();通常の内部クラスは、外部クラスを構成するインスタンスのみを表示し、外部クラスインスタンスを通過する.New内部クラス名()は、Baseb=new Base()のような内部クラスインスタンスを構築する.new Sub();
2、静的内部クラスは静的メンバーを持つことができ、静的内部クラスではなく静的メンバーを持つことができない.
3、静的内部クラスの非静的メンバーは外部クラスの静的変数にアクセスでき、外部クラスの非静的変数にアクセスできない.
4.非静的内部クラスの非静的メンバーは、外部クラスの非静的変数にアクセスすることができる.
未完待機!