首頁 >Java >java教程 >講解Java中如何建構內部類別物件以及存取對象

講解Java中如何建構內部類別物件以及存取對象

高洛峰
高洛峰原創
2017-01-20 17:42:381315瀏覽

透過反射建構內部類別物件
先在 javalang 套件下寫一個包含內部類別的類別:

package javalang;
 
public class Outer {
  public static class Inner1{}
}

注意這個類別是 public static,後面我們慢慢把這些修飾符去掉。

要想透過反射來創建 Inner1 對象,首先要獲得 Inner1 的 Class 對象。我們在 Outer 中寫上 main 方法:

public class Outer {
  public static class Inner1{}
   
  public static void main(String[] args) {
    System.out.println(Inner1.class);
  }
}

輸出結果:

class javalang.Outer$Inner1

然後我們試試看這個類別名稱對不對:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1"));
}

運行一下,沒錯。然後就是用它來創建物件。創建物件要靠建構方法。這個類別有沒有構造方法呢?我們可以這樣寫:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors().length);
}

 

運行一下,輸出 1。看來有。然後再看看這個構造方法是什麼樣子的:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors()[0]);
}

 

輸出結果:public javalang.Outer$Inner1()。這就是缺省構造方法嘛。所以我們可以這樣寫:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getConstructors()[0].newInstance();
}

輸出結果:javalang.Outer$Inner1@ca0b6。這說明執行成功了。

接下來我們把 Inner 的 public 關鍵字拿掉,然後再運行。結果報錯了:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0

這表示沒有找到構造方法。真的沒有嗎?我們把 main 方法改回來:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getConstructors().length);
}

輸出結果:0。真的沒有構造方法嗎?其實不是,只是構造方法不是公開的。這時我們必須用 getDeclaredConstructors() 來得到:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getDeclaredConstructors().length);
}

輸出結果:1。這就把構造方法找到了。然後我們繼續呼叫這個建構方法:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getDeclaredConstructors()[0].newInstance());
}

輸出結果:javalang.Outer$Inner1@ca0b6。現在我們可以用反射來建構非公開內部類別的物件了。

接下來,我們再把 static 關鍵字拿掉。這時候報錯了:
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments

這說明什麼呢?我們呼叫的時候沒有傳參數,而錯誤內容就是說參數數量不正確。那麼這個構造方法有什麼參數呢?讓我們改一下程式碼來看看:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getDeclaredConstructors()[0]);
}

輸出結果:javalang.Outer$Inner1(javalang.Outer)

原來建構方法裡面需要一個 Outer 類型的參數。這好辦:

public static void main(String[] args) throws Exception {
  System.out.println(Class.forName("javalang.Outer$Inner1")
      .getDeclaredConstructors()[0].newInstance(new Outer()));
}

輸出結果:

javalang.Outer$Inner1@ca0b6

OK,原來如此。看來非靜態的內部類別沒有缺省的建構方法,建構時需要傳一個外部類別的實例作為參數。


Java: 如何存取一個物件
對 Java 初學者來說一個頭痛的問題是,如何決定把一個物件是定義為方法變量,還是定義為成員變數?
 
最開始初學者還不會在乎這一點。但是當寫出來的程式越來越大,類別越來越多時,這種苦惱也應運而生。
 
但我這裡要寫的是:如何隨心所欲的安排一個對象,讓你隨時可以訪問。掌握了這一點,你就可以自由的決定將一個物件放在什麼地方了。
 
下面舉一個簡單的例子:

public class AccessingObject {
   
  public static void main(String[] args) {
    Date date = new Date();
  }
   
  // 获得 date 对象一小时后的时间
  private static void anHourLater() {
    // 这里如何获得 main() 方法中的 date 变量?
  }
}

正如 anHourLater() 方法中所描述的,想要獲得 date 一小時後的時間。怎麼辦呢?有下面幾種方法。
 
(1)參數傳遞

public class AccessingObject {
   
  public static void main(String[] args) {
    Date date = new Date();
    anHourLater(date);
  }
   
  // 获得 date 对象一小时后的时间
  private static void anHourLater(Date d) {
    Date anHourLater = new Date(d.getTime() + 3600000);
  }
}

   

(2)定義為成員。成員可以由所有方法訪問,成員的初始化可以放在定義的地方,也可以放在任何一個方法裡。

public class AccessingObject {
   
  private static Date date;
   
  public static void main(String[] args) {
    date = new Date();
    anHourLater();
  }
   
  // 获得 date 对象一小时后的时间
  private static void anHourLater() {
    Date anHourLater = new Date(date.getTime() + 3600000);
  }
}

   

(3)放到另一個類當中去。在下面的例子中,DateHolder.date 可以被同一個套件中的所有類別訪問,而不僅限於 AccessingObject 類別。

public class AccessingObject {
   
  public static void main(String[] args) {
    DateHolder.date = new Date();
  }
   
  // 获得 date 对象一小时后的时间
  private static void anHourLater() {
    Date anHourLater = new Date(DateHolder.date.getTime() + 3600000);
  }
}
   
class DateHolder {
  public static Date date;
}

   

這三個例子比較起來,前兩個只能在類的內部使用,相對比較安全。如果你不希望這個物件被別的類別直接修改,就不要用第三種方式。
 
第一種方式和第二種方式的區別在於:如果一個物件只在方法中使用,那麼當方法執行完後,這個物件能夠很容易的被回收(注意,不是馬上被回收)。如果定義為類別的成員,那麼只有當它所在的類別被回收之後,這個物件才會被回收。顯然,第一種方式是最節約資源的,我們應該盡量使用第一種方式。
 
回頭再看看這三個例子,如果 main() 方法要獲得 anHourLater() 方法中得出的一小時後時間,它也有幾種對應的方式。後兩個例子就不用改了,date 物件是可以直接存取的;第一個例子,有兩種修改方式:
 
(1)作為回傳值

public class AccessingObject {
   
  public static void main(String[] args) {
    Date date = new Date();
    Date anHourLater = anHourLater(date);
  }
   
  // 获得 date 对象一小时后的时间
  private static Date anHourLater(Date d) {
    return new Date(d.getTime() + 3600000);
  }
}

   

(2)直接修改參數的參數的內容

public class AccessingObject {
   
  public static void main(String[] args) {
    Date date = new Date();
    anHourLater(date);
  }
   
  // 获得 date 对象一小时后的时间
  private static void anHourLater(Date d) {
    d.setTime(d.getTime() + 3600000);
  }
}

   

其中第二種方法要慎用,因為隨便動人家的東西是不對的,你不知道方法的調用者喜不喜歡你這麼做。

更多講解Java中如何建構內部類別物件以及存取物件相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn