1. 程式人生 > >第六章 內部類

第六章 內部類

內部類

為什麼要使用內部類?

  • 內部類可以訪問該類定義所在的作用域中的所有的資料,包括私有資料
  • 內部類可以對同一個包的其他類隱藏起來
  • 當要定義一個回撥函式並且不想編寫大量程式碼時,使用匿名內部類比較方便。

使用內部類訪問物件的狀態

內部類的物件總有一個隱式引用。它指向了建立它的外部類物件。
在一個內部類的物件被建立之時,它所在類的物件的引用被作為引數,傳遞給這個內部類的隱式建構函式。

內部類的特殊語法規則

  • OuterClass.this 引用外部類的物件 egTalking.this.beep
  • ActionListener listenr =this.new TimePrinter();在這裡,最新構造的actionListener物件的外圍類的引用被設定為建立內部類物件的方法中的this引用。
  • 在外圍類的作用域之外,Outerclass.innerclass可以這樣引用內部類
  • 內部類中所有的靜態域必須是final

內部類是否有用,必要和安全?

與常規類相比,內部類訪問外圍類私有資料的特性更強大

內部實現?

  • 編譯器會在外圍類中新增static boolean access$0(TalkingClock)
    這樣的access$0方法

區域性內部類

區域性內部類適用於內部類的物件只使用一次的情況。

  • 區域性類不能用public 或 private修飾。
  • 區域性類的優勢是,只在一個方法內定義,只被一個方法使用。其他類不知道該區域性類的存在。

由外部方法訪問變數 P252

與內部類相比較,區域性類的另一個優點是,可以訪問區域性變數。
區域性類的方法只可以引用定義為final的區域性變數。對於counter這種final不方便的情況,可以用長為1的陣列來儲存。

匿名內部類

匿名內部類的格式?

new SuperType(construction parameters)
{ inner class methods and data; }

注意匿名類沒有類名。故沒有構造器。
如果有引數,作用是啥?引數傳遞給超類的構造器。(上面就是個例子)
但是,對於內部類實現介面的時候:不能有引數!

new InterfaceType()
{
	inner class methods and data;
}

下面是用匿名內部類實現語音時鐘程式的原始碼:

/**
 * A clock that prints the time in regular intervals.
 */
class TalkingClock
{
   /**
    * Starts the clock.
    * @param interval the interval between messages (in milliseconds)
    * @param beep true if the clock should beep
    */
   public void start(int interval, boolean beep)
   {
      ActionListener listener = new ActionListener()//這是一個介面
         {
            public void actionPerformed(ActionEvent event)
            {
               System.out.println("At the tone, the time is " + new Date());
               if (beep) Toolkit.getDefaultToolkit().beep();
            }
         };
      Timer t = new Timer(interval, listener);
      t.start();
   }
}

但此處用lambda表示式會更加的簡潔。

小注釋:匿名陣列列表:

invite
(
	new ArrayList<String>()
	{
		{  
			add("Harry");
			add("Tony");
		}
	}
)

匿名子類在使用equals方法時要特別當心!
getClass()方法在使用時呼叫的是this.getClass(),但是靜態方法沒有內部類,這就不行了
怎麼辦?

new Object(){}.getClass.getEnclosingClass()

這樣就得到了包含這個靜態方法的類。可以算是匿名子類的一個應用吧。

靜態內部類

為什麼要靜態?
有時候不需要內部類引用外圍類的物件,所以宣告該內部類為static,取消產生引用。
靜態內部類的物件除了沒有對生成它的外圍類物件的引用特權外,與其他所有內部類完全一樣。

與常規內部類不同,靜態內部類可以有靜態域和方法。
下面是一個靜態內部類的例子:

class ArrayAlg
{
   /**
    * A pair of floating-point numbers
    */
   public static class Pair
   {
      private double first;
      private double second;

      /**
       * Constructs a pair from two floating-point numbers
       * @param f the first number
       * @param s the second number
       */
      public Pair(double f, double s)
      {
         first = f;
         second = s;
      }

      /**
       * Returns the first number of the pair
       * @return the first number
       */
      public double getFirst()
      {
         return first;
      }

      /**
       * Returns the second number of the pair
       * @return the second number
       */
      public double getSecond()
      {
         return second;
      }
   }

   /**
    * Computes both the minimum and the maximum of an array
    * @param values an array of floating-point numbers
    * @return a pair whose first element is the minimum and whose second element
    * is the maximum
    */
   public static Pair minmax(double[] values)
   {
      double min = Double.POSITIVE_INFINITY;
      double max = Double.NEGATIVE_INFINITY;
      for (double v : values)
      {
         if (min > v) min = v;
         if (max < v) max = v;
      }
      return new Pair(min, max);
   }
}

下面是呼叫的方法:

public static void main(String[] args)
   {
      double[] d = new double[20];
      for (int i = 0; i < d.length; i++)
         d[i] = 100 * Math.random();
      ArrayAlg.Pair p = ArrayAlg.minmax(d);
      System.out.println("min = " + p.getFirst());
      System.out.println("max = " + p.getSecond());
   }

注意此處,內部類物件在靜態方法中構造,所以必須使用靜態內部類