講解Java中如何構(gòu)造內(nèi)部類對(duì)象以及訪問對(duì)象
通過反射構(gòu)造內(nèi)部類對(duì)象
首先在 javalang 包下寫一個(gè)包含內(nèi)部類的類:
package javalang;
public class Outer {
public static class Inner1{}
}
注意這個(gè)類是 public static,后面我們慢慢把這些修飾符去掉。
要想通過反射來創(chuàng)建 Inner1 對(duì)象,首先要獲得 Inner1 的 Class 對(duì)象。我們?cè)?Outer 中寫上 main 方法:
public class Outer {
public static class Inner1{}
public static void main(String[] args) {
System.out.println(Inner1.class);
}
}
輸出結(jié)果:
class javalang.Outer$Inner1
然后我們?cè)囈幌逻@個(gè)類名對(duì)不對(duì):
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1"));
}
運(yùn)行一下,沒錯(cuò)。然后就是用它來創(chuàng)建對(duì)象。創(chuàng)建對(duì)象要靠構(gòu)造方法。這個(gè)類有沒有構(gòu)造方法呢?我們可以這么寫:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors().length);
}
運(yùn)行一下,輸出 1??磥碛?。然后看看這個(gè)構(gòu)造方法是什么樣子的:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1").getConstructors()[0]);
}
輸出結(jié)果:public javalang.Outer$Inner1()。這就是缺省構(gòu)造方法嘛。所以我們可以這樣寫:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getConstructors()[0].newInstance();
}
輸出結(jié)果:javalang.Outer$Inner1@ca0b6。這說明執(zhí)行成功了。
接下來我們把 Inner 的 public 關(guān)鍵字去掉,然后再運(yùn)行。結(jié)果報(bào)錯(cuò)了:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
這說明沒有找到構(gòu)造方法。真的沒有嗎?我們把 main 方法改回來:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getConstructors().length);
}
輸出結(jié)果:0。真的沒有構(gòu)造方法嗎?其實(shí)不是,只是構(gòu)造方法不是公開的。這時(shí)我們必須用 getDeclaredConstructors() 來獲得:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getDeclaredConstructors().length);
}
輸出結(jié)果:1。這就把構(gòu)造方法找到了。然后我們繼續(xù)調(diào)用這個(gè)構(gòu)造方法:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getDeclaredConstructors()[0].newInstance());
}
輸出結(jié)果:javalang.Outer$Inner1@ca0b6。現(xiàn)在我們可以用反射來構(gòu)造非公開內(nèi)部類的對(duì)象了。
接下來,我們?cè)侔?static 關(guān)鍵字去掉。這時(shí)候報(bào)錯(cuò)了:
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
這說明什么呢?我們調(diào)用的時(shí)候沒有傳參數(shù),而錯(cuò)誤內(nèi)容就是說參數(shù)數(shù)量不正確。那么這個(gè)構(gòu)造方法有什么參數(shù)呢?我們改一下代碼看看:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getDeclaredConstructors()[0]);
}
輸出結(jié)果:javalang.Outer$Inner1(javalang.Outer)
原來構(gòu)造方法里面需要一個(gè) Outer 類型的參數(shù)。這好辦:
public static void main(String[] args) throws Exception {
System.out.println(Class.forName("javalang.Outer$Inner1")
.getDeclaredConstructors()[0].newInstance(new Outer()));
}
輸出結(jié)果:
javalang.Outer$Inner1@ca0b6
OK,原來如此??磥矸庆o態(tài)的內(nèi)部類沒有缺省的構(gòu)造方法,構(gòu)造時(shí)需要傳一個(gè)外部類的實(shí)例作為參數(shù)。
Java: 如何訪問一個(gè)對(duì)象
對(duì) Java 初學(xué)者來說一個(gè)頭疼的問題是,如何決定把一個(gè)對(duì)象是定義為方法變量,還是定義為成員變量?
最開始初學(xué)者還不會(huì)關(guān)心這點(diǎn)。但是當(dāng)寫出來的程序越來越大,類越來越多時(shí),這種苦惱也應(yīng)運(yùn)而生。
但我這里要寫的是:如何隨心所欲的安排一個(gè)對(duì)象,讓你隨時(shí)可以訪問。掌握了這點(diǎn),你就可以自由的決定將一個(gè)對(duì)象放在什么地方了。
下面舉一個(gè)簡(jiǎn)單的例子:
public class AccessingObject {
public static void main(String[] args) {
Date date = new Date();
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static void anHourLater() {
// 這里如何獲得 main() 方法中的 date 變量?
}
}
正如 anHourLater() 方法中描述的,想要獲得 date 一小時(shí)后的時(shí)間。怎么辦呢?有下面幾種方法。
(1)參數(shù)傳遞
public class AccessingObject {
public static void main(String[] args) {
Date date = new Date();
anHourLater(date);
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static void anHourLater(Date d) {
Date anHourLater = new Date(d.getTime() + 3600000);
}
}
(2)定義為成員。成員可以由所有方法訪問,成員的初始化可以放在定義的地方,也可以放在任何一個(gè)方法里。
public class AccessingObject {
private static Date date;
public static void main(String[] args) {
date = new Date();
anHourLater();
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static void anHourLater() {
Date anHourLater = new Date(date.getTime() + 3600000);
}
}
(3)放到另外一個(gè)類當(dāng)中去。在下面的例子中,DateHolder.date 可以被同一個(gè)包中的所有類訪問,而不僅限于 AccessingObject 類。
public class AccessingObject {
public static void main(String[] args) {
DateHolder.date = new Date();
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static void anHourLater() {
Date anHourLater = new Date(DateHolder.date.getTime() + 3600000);
}
}
class DateHolder {
public static Date date;
}
這三個(gè)例子比較起來,前兩個(gè)只能在類的內(nèi)部使用,相對(duì)比較安全。如果你不希望這個(gè)對(duì)象被別的類直接修改,就不要用第三種方式。
第一種方式和第二種方式的區(qū)別在于:如果一個(gè)對(duì)象只在方法中使用,那么當(dāng)方法執(zhí)行完后,這個(gè)對(duì)象能夠很容易的被回收(注意,不是馬上被回收)。如果定義為類的成員,那么只有當(dāng)它所在的類被回收之后,這個(gè)對(duì)象才會(huì)被回收。顯然,第一種方式是最節(jié)約資源的,我們應(yīng)該盡量使用第一種方式。
回頭再看看這三個(gè)例子,如果 main() 方法要獲得 anHourLater() 方法中得出的一小時(shí)后時(shí)間,它也有幾種對(duì)應(yīng)的方式。后兩個(gè)例子就不用改了,date 對(duì)象是可以直接訪問的;第一個(gè)例子,有兩種修改方式:
(1)作為返回值
public class AccessingObject {
public static void main(String[] args) {
Date date = new Date();
Date anHourLater = anHourLater(date);
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static Date anHourLater(Date d) {
return new Date(d.getTime() + 3600000);
}
}
(2)直接修改參數(shù)的內(nèi)容
public class AccessingObject {
public static void main(String[] args) {
Date date = new Date();
anHourLater(date);
}
// 獲得 date 對(duì)象一小時(shí)后的時(shí)間
private static void anHourLater(Date d) {
d.setTime(d.getTime() + 3600000);
}
}
其中第二種方法要慎用,因?yàn)殡S便動(dòng)人家的東西是不對(duì)的,你不知道方法的調(diào)用者喜不喜歡你這么做。
- java匿名內(nèi)部類實(shí)例簡(jiǎn)析
- Java內(nèi)部類的繼承(全)
- 基于java內(nèi)部類作用的深入分析
- java中關(guān)于內(nèi)部類的使用詳解
- java 內(nèi)部類(匿名類,匿名對(duì)象,靜態(tài)內(nèi)部類)詳解及實(shí)例
- 在java中 利用匿名內(nèi)部類進(jìn)行較簡(jiǎn)潔的雙括弧初始化的方法
- Java內(nèi)部類之間的閉包和回調(diào)詳解
- JAVA 內(nèi)部類詳解及實(shí)例
- 老生常談 java匿名內(nèi)部類
- Java嵌套類和內(nèi)部類詳解
- Java中的匿名內(nèi)部類小結(jié)
- Java內(nèi)部類原理與用法實(shí)例總結(jié)
相關(guān)文章
iOS開發(fā)中Quartz2D控制圓形縮放和實(shí)現(xiàn)刷幀效果
這篇文章主要介紹了iOS開發(fā)中Quartz2D控制圓形縮放和實(shí)現(xiàn)刷幀效果的方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12
iOS應(yīng)用開發(fā)中UITableView的分割線的一些設(shè)置技巧
這篇文章主要介紹了iOS應(yīng)用開發(fā)中UITableView分割線的一些設(shè)置技巧,包括消除分割線的方法,示例代碼為傳統(tǒng)的Objective-C語言,需要的朋友可以參考下2016-03-03
iOS中UIAlertController設(shè)置自定義標(biāo)題與內(nèi)容的方法
UIAlertController是iOS8推出的新概念,取代了之前的 UIAlertView和UIActionSheet(雖然現(xiàn)在仍可以使用,但是會(huì)有警告)。下面這篇文章主要給大家介紹了關(guān)于iOS中UIAlertController如何設(shè)置自定義標(biāo)題與內(nèi)容的相關(guān)資料,需要的朋友可以參考下。2017-10-10
iOS?WKWebView秒開方案實(shí)戰(zhàn)記錄
從iOS8開始,就引入了新的瀏覽器控件WKWebView,用于取代UIWebView,下面這篇文章主要給大家介紹了關(guān)于iOS?WKWebView秒開方案的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
iOS使用 CABasicAnimation 實(shí)現(xiàn)簡(jiǎn)單的跑馬燈(無cpu暴漲)
本篇文章主要介紹了iOS使用 CABasicAnimation 實(shí)現(xiàn)簡(jiǎn)單的跑馬燈(無cpu暴漲),具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01
iOS開發(fā)中的幾個(gè)手勢(shì)操作實(shí)例分享
這篇文章主要介紹了iOS開發(fā)中的幾個(gè)手勢(shì)操作實(shí)例分享,編寫代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-09-09

