thisが代表するケースについて

1798 ワード

親クラスは、子クラスのインスタンス変数にアクセスできないことを知っています.ここには特別なケースがあります
class Base {
    private int i = 2;
    public Base(){
         System.out.println(this.i);
         this.display();
         //System.out.println(this.getClass());
         //this.test();
    }
    public void display(){
         System.out.println(i);
    }
}
public class Sub extends Base {
     private int i = 22;
 
     public Sub(){
         i = 222;
     }
 
     public void display(){
         System.out.println(i);
     }
 
     public static void main(String[] args) {
         new Test(); ①
     }
 
     public void test(){
            
     }
}

結果は意外で、2,2ではない.2,0である.
解析:1でコードを出し,Subオブジェクトを新規作成し,SubクラスのコンストラクタでBaseクラスの無パラメトリックコンストラクタを暗黙的に呼び出す.ベースのコンストラクション関数を解析する前に、まず3つの点を理解します.
1)Javaクラスのオブジェクトは,コンストラクション関数によって作成されるのではなく,コンストラクション関数に初期値が付与される前にクラスメンバー変数にメモリ領域が割り当てられ,メモリ内の値は空である.また、クラスの定義時に付与されたメンバー変数と非静的コードブロックの初期化要素は、メモリ(デフォルト値を格納)を割り当ててから、コンストラクション関数に集計して初期値を付与し、コンストラクション関数の元のコードの前に順番に並べられます.
2)子と親に複数の同じ名前のインスタンス変数がある場合、子のインスタンス変数は親の同じ名前のインスタンス変数を上書きすることはできません.したがって、Subクラスをインスタンス化する場合は、親クラスのiと子クラスのiを格納するために2つのメモリ領域を割り当てる必要があります.この場合、2つのiの値は0になります.
3)thisがコンストラクタにある場合、初期化中のオブジェクトを表します.ソースコードから見ると、これはBaseのコンストラクタで実行されます.しかし実際には、現在初期化されているJavaクラスはSubである、Subのコンストラクタで親クラスのデフォルトコンストラクタが暗黙的に呼び出されているため、thisはSubクラスである、という点でthis.getClass()検証.
では問題が来ました.thisはSubクラスを表していますが、this.iは2を出力しますが、this.display()は0を出力します.
これは、このBaseのコンストラクタにあるため、コンパイルタイプはBaseですが、参照するオブジェクトはSubタイプ、すなわち実行時タイプはSubタイプであり、これはthisによってもよい.test()は、今回のコンパイルが失敗したため検証します.
要約:変数のコンパイル時のタイプと実行時のタイプが異なる場合、その変数によって参照されるオブジェクトのインスタンス変数にアクセスすると、そのインスタンス変数の値は宣言されたタイプによって決まりますが、その変数によって参照されるオブジェクトのインスタンスメソッドにアクセスすると、そのメソッドの動作は参照されるオブジェクトタイプによって決まります.
だからこれはiの値はBaseのi,this.display()はSubの方法であり、iは0である.