Java中內部類揭祕(一):外部類與非靜態內部類的”相互可見性“

好文值得轉~

我們都知道,非靜態內部類可以訪問外部類的私有成員(包括私有變量和方法),這也正是使用非靜態內部類與普通類的一個重要區別:非靜態內部類是依賴於外部類對象而存在的,這種依賴就包括它要能自由地訪問外部類對象的所有成員(因爲private成員都可以訪問了,其他權限的成員更不在話下。不過一般來說一個內部類只會訪問外部類的部分成員而不是全部)。比如心臟作爲單獨的一個類存在可能沒有太大的意義,它必須依附於具體的Person對象存在纔有意義,而且心臟它要能夠自由地訪問Person對象的一些成員,如血液、營養等。

顯然,外部類對於非靜態內部類而言是完全透明的。但是實際上,外部類與非靜態內部類的另一個特徵雖然不常用,卻也值得注意,那就是非靜態內部類其實跟外部類的其他成員類似,只是它的一個成員而已,因而即使非靜態內部類的修飾符爲private、即使非靜態內部類的構造器修飾符爲private,外部類也可以新建非靜態內部類的對象。如下例所示:

 

import java.util.*;
 
class Car
{
  private float gasAmount;
  private String gasType;
  public Car(float gasAmount,String gasType)
  {
    this.gasAmount=gasAmount;
    this.gasType=gasType;
    new Engine();
  }
 
  private void print(String msg)
  {
     System.out.println(msg);
   }
  private class Engine
  {
    private int rotateSpeed;
    private Engine()
    {
      if(gasType==93#&&gasAmount>0)
      {
          rotateSpeed=1500;
          print(Gas amount is +String.valueOf(gasAmount)+ gallon now.Engine starts successfully);
      }
      else if(gasType==93#&&gasAmount<=0)
      {
          rotateSpeed=0;
          print(Engine starts failed! Please add fuel first!);
       }
      else
      {
          rotateSpeed=0;
          print(Gas type is not correct!);
       }
       
    }
  }
}
 
 
public class OuterSample
{
  public static void main(String[]args)
  {
     new Car(2.0f,93#);
     new Car(0.0f,93#);
  }
}


輸出結果如下圖所示:

\

顯然,由輸出結果可看出:第一,雖然非靜態內部類的修飾符和構造器均爲private,但是外部類仍然可以創建內部類對象;第二,非靜態內部類可以使用外部類的private成員(如此處的private成員變量gasType及gasAmount);

另一個常常被人忽略的地方是:在外部類的方法中,也可以通過創建非靜態內部類的對象來訪問內部類包括private成員在內的所有成員,不過注意必須是外部類的實例成員才行,而不能在外部類的靜態成員(包括靜態方法和靜態初始化塊)中使用非靜態內部類,原因很簡單:非靜態內部類可看作是外部類的一個實例成員,而靜態成員不能訪問實例成員。如下例所示:

import java.util.*;
 
class Car
{
  private float gasAmount;
  private String gasType;
  private Engine engine;
  public Car(float gasAmount,String gasType)
  {
    this.gasAmount=gasAmount;
    this.gasType=gasType;
    engine=new Engine();
  }
 
  public void printRotateSpeed()
  {
    //其實寫成print(Rotate speed is +String.valueOf(new Engine().rotateSpeed));也行,但是不太符合實際,因爲一車對應一引擎
     print(Rotate speed is +String.valueOf(engine.rotateSpeed));
   }
  private void print(String msg)
  {
     System.out.println(msg);
   }
  private class Engine
  {
    private int rotateSpeed;
    private Engine()
    {
      if(gasType==93#&&gasAmount>0)
      {
          rotateSpeed=1500;
          print(Gas amount is +String.valueOf(gasAmount)+ gallon now.Engine starts successfully);
      }
      else if(gasType==93#&&gasAmount<=0)
      {
          rotateSpeed=0;
          print(Engine starts failed! Please add fuel first!);
       }
      else
      {
          rotateSpeed=0;
          print(Gas type is not correct!);
       }
       
    }
  }
}
 
 
public class OuterSample
{
  public static void main(String[]args)
  {
     Car car01=new Car(2.0f,93#);
     car01.printRotateSpeed();
     Car car02=new Car(0.0f,93#);
     car02.printRotateSpeed();
  }
}
輸出結果如下圖: 

\
從輸出結果可以看出,在外部類的方法printRotateSpeed()中,通過非靜態內部類的對象來a訪問了其private成員rotateSpeed,這其實跟實際中的情況很像,即發動機從汽車處獲得燃料信息,汽車再從發動機處獲得轉速並顯示在儀表盤上。

綜上,非靜態內部類可自由訪問外部類包括privated成員在內的所有成員,外部類也可通過創建內部類的對象來訪問其包括private成員在內的所有成員,所以它們雖然在類層面不是相互可見的,但是從廣義上來說具有相互可見性,這也是我在題目上打上雙引號的原因。


發佈了41 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章