熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

方法和作用域中的內部類

2022-06-13   來源: Java核心技術 

  至此我們已基本理解了內部類的典型用途對那些涉及內部類的代碼通常表達的都是單純的內部類非常簡單且極易理解然而內部類的設計非常全面不可避免地會遇到它們的其他大量用法——假若我們在一個方法甚至一個任意的作用域內創建內部類有兩方面的原因促使我們這樣做
  
  () 正如前面展示的那樣我們准備實現某種形式的接口使自己能創建和返回一個句柄
  
  () 要解決一個復雜的問題並希望創建一個類用來輔助自己的程序方案同時不願意把它公開
  
  在下面這個例子裡將修改前面的代碼以便使用
  
  () 在一個方法內定義的類
  
  () 在方法的一個作用域內定義的類
  
  () 一個匿名類用於實現一個接口
  
  () 一個匿名類用於擴展擁有非默認構建器的一個類
  
  () 一個匿名類用於執行字段初始化
  
  () 一個匿名類通過實例初始化進行構建(匿名內部類不可擁有構建器)
  
  所有這些都在innerscopes包內發生首先來自前述代碼的通用接口會在它們自己的文件裡獲得定義使它們能在所有的例子裡使用
  
  //: Destinationjava
  package cinnerscopes;
  
  interface Destination {
   String readLabel();
  } ///:~
  
  由於我們已認為Contents可能是一個抽象類所以可采取下面這種更自然的形式就象一個接口那樣
  
  //: Contentsjava
  package cinnerscopes;
  
  interface Contents {
   int value();
  } ///:~
  
  盡管是含有具體實施細節的一個普通類但Wrapping也作為它所有衍生類的一個通用接口使用
  
  //: Wrappingjava
  package cinnerscopes;
  
  public class Wrapping {
   private int i;
   public Wrapping(int x) { i = x; }
   public int value() { return i; }
  } ///:~
  
  在上面的代碼中我們注意到Wrapping有一個要求使用自變量的構建器這就使情況變得更加有趣了
  
  第一個例子展示了如何在一個方法的作用域(而不是另一個類的作用域)中創建一個完整的類
  
  //: Parceljava
  // Nesting a class within a method
  package cinnerscopes;
  
  public class Parcel {
   public Destination dest(String s) {
    class PDestination
      implements Destination {
     private String label;
     private PDestination(String whereTo) {
      label = whereTo;
     }
     public String readLabel() { return label; }
    }
    return new PDestination(s);
   }
   public static void main(String[] args) {
    Parcel p = new Parcel();
    Destination d = pdest(Tanzania);
   }
  } ///:~
  
  PDestination類屬於dest()的一部分而不是Parcel的一部分(同時注意可為相同目錄內每個類內部的一個內部類使用類標識符PDestination這樣做不會發生命名的沖突)因此PDestination不可從dest()的外部訪問請注意在返回語句中發生的上溯造型——除了指向基礎類Destination的一個句柄之外沒有任何東西超出dest()的邊界之外當然不能由於類PDestination的名字置於dest()內部就認為在dest()返回之後PDestination不是一個有效的對象
  
  下面這個例子展示了如何在任意作用域內嵌套一個內部類
  
  //: Parceljava
  // Nesting a class within a scope
  package cinnerscopes;
  
  public class Parcel {
   private void internalTracking(boolean b) {
    if(b) {
     class TrackingSlip {
      private String id;
      TrackingSlip(String s) {
       id = s;
      }
      String getSlip() { return id; }
     }
     TrackingSlip ts = new TrackingSlip(slip);
     String s = tsgetSlip();
    }
    // Cant use it here! Out of scope:
    //! TrackingSlip ts = new TrackingSlip(x);
   }
   public void track() { internalTracking(true); }
   public static void main(String[] args) {
    Parcel p = new Parcel();
    ptrack();
   }
  } ///:~
  
  TrackingSlip類嵌套於一個if語句的作用域內這並不意味著類是有條件創建的——它會隨同其他所有東西得到編譯然而在定義它的那個作用域之外它是不可使用的除這些以外它看起來和一個普通類並沒有什麼區別
  
  下面這個例子看起來有些奇怪
  
  //: Parceljava
  // A method that returns an anonymous inner class
  package cinnerscopes;
  
  public class Parcel {
   public Contents cont() {
    return new Contents() {
     private int i = ;
     public int value() { return i; }
    }; // Semicolon required in this case
   }
   public static void main(String[] args) {
    Parcel p = new Parcel();
    Contents c = nt();
   }
  } ///:~
  
  cont()方法同時合並了返回值的創建代碼以及用於表示那個返回值的類除此以外這個類是匿名的——它沒有名字而且看起來似乎更讓人摸不著頭腦的是我們准備創建一個Contents對象
  
  return new Contents()
  
  但在這之後在遇到分號之前我們又說等一等讓我先在一個類定義裡再耍一下花招
  
  return new Contents() {
  private int i = ;
  public int value() { return i; }
  };
  
  這種奇怪的語法要表達的意思是創建從Contents衍生出來的匿名類的一個對象由new表達式返回的句柄會自動上溯造型成一個Contents句柄匿名內部類的語法其實要表達的是
  
  class MyContents extends Contents {
  private int i = ;
  public int value() { return i; }
  }
  return new MyContents();
  
  在匿名內部類中Contents是用一個默認構建器創建的下面這段代碼展示了基礎類需要含有自變量的一個構建器時做的事情
  
  //: Parceljava
  // An anonymous inner class that calls the
  // baseclass constructor
  package cinnerscopes;
  
  public class Parcel {
   public Wrapping wrap(int x) {
    // Base constructor call:
    return new Wrapping(x) {
     public int value() {
      return supervalue() * ;
     }
    }; // Semicolon required
   }
   public static void main(String[] args) {
    Parcel p = new Parcel();
    Wrapping w = pwrap();
   }
  } ///:~
  
  也就是說我們將適當的自變量簡單地傳遞給基礎類構建器在這兒表現為在new Wrapping(x)中傳遞x匿名類不能擁有一個構建器這和在調用super()時的常規做法不同
  
  在前述的兩個例子中分號並不標志著類主體的結束(和C++不同)相反它標志著用於包含匿名類的那個表達式的結束因此它完全等價於在其他任何地方使用分號
  
  若想對匿名內部類的一個對象進行某種形式的初始化此時會出現什麼情況呢?由於它是匿名的沒有名字賦給構建器所以我們不能擁有一個構建器然而我們可在定義自己的字段時進行初始化
  
  //: Parceljava
  // An anonymous inner class that performs
  // initialization A briefer version
  // of Parceljava
  package cinnerscopes;
  
  public class Parcel {
   // Argument must be final to use inside
   // anonymous inner class:
   public Destination dest(final String dest) {
    return new Destination() {
     private String label = dest;
     public String readLabel() { return label; }
    };
   }
   public static void main(String[] args) {
    Parcel p = new Parcel();
    Destination d = pdest(Tanzania);
   }
  } ///:~
  
  若試圖定義一個匿名內部類並想使用在匿名內部類外部定義的一個對象則編譯器要求外部對象為final屬性這正是我們將dest()的自變量設為final的原因如果忘記這樣做就會得到一條編譯期出錯提示
  
  只要自己只是想分配一個字段上述方法就肯定可行但假如需要采取一些類似於構建器的行動又應怎樣操作呢?通過Java 的實例初始化我們可以有效地為一個匿名內部類創建一個構建器
  
  //: Parceljava
  // Using instance initialization to perform
  // construction on an anonymous inner class
  package cinnerscopes;

From:http://tw.wingwit.com/Article/program/Java/hx/201311/27008.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.