該篇文章涉及到了Java可訪問特性以及內部類的一些內容,向讀者展示了一個內部類的非凡的現象,通過這個例子,使開發者了解到一些他們以前可能沒有注重到的細節,也許可以幫助開發者更透徹的了解java的可訪問特性、內部類和虛擬機。並且通過對這些細節的分析,可能會對開發者思考、分析問題,以及適當的使用工具有所啟迪。
java的訪問修改符(Access modifier)包括:Default-Access、public、private、protected四種。並不是所有的情況都可以使用全部四種訪問修改符,有的情況下使用某些訪問修改符是沒有意義的,例如:假如一個類不是內部類,則不能使用private作為該類的訪問修改符,編譯下面的代碼:
private class test
{ ... }
jdk編譯器將給出“modifier private not allowed here”錯誤提示。因為private特性只能由定義它的那個類使用,假如上面的代碼通過編譯,則不會有任何情況可以使用test類,那麼也就不會有任何意義。
假如一個類沒有定義任何構造函數,則編譯器將生成一個缺省的構造函數,該構造函數的訪問修改符和類的訪問修改符相同,例如:
class test將生成test()構造函數public class test將生成public test()構造函數。
在使用內部類的情況,上述的特性將使編譯器表現出一個非凡現象。需要說明的是,下面的例子僅針對Windows系統下jdk編譯器,作者並沒有嘗試使用其他的編譯器的情況。但由於java編譯器生成的是class文件這種中間形式的代碼,所以下面的討論應該適用於任何符合java標准的編譯器。
編譯下面的代碼:
public class Wrapper
{
private class InnerClass
{}
private void testInnerClass()
{
InnerClass inner = new InnerClass();
}
public static void main(String[] args)
{
Wrapper wrapper = new Wrapper();
wrapper.testInnerClass();
}
}
將產生三個class文件:Wrapper、Wrapper$InnerClass和Wrapper$1。
對於前兩個文件,了解內部類的讀者都會理解,但第三個類Wrapper$1的作用是什麼呢?
使用java的反射機制,或者使用javap反匯編器,將發現Wrapper$1類沒有任何成員變量和方法,而Wrapper$InnerClass則除了有一個private Wrapper$InnerClass()構造方法外,還有一個Wrapper$InnerClass(Wrapper$1)構造方法,使用javap,你將發現Wrapper$InnerClass(Wrapper$1)並沒有使用Wrapper$1類型的參數,而只是直接調用了private Wrapper$InnerClass()。假如讀者仔細思考一下創建一個新的類實例的過程,大概已經明白了產生上述現象的原因:當程序試圖創建一個Wrapper$InnerClass的類實例時,卻不能使用其缺省的構造函數,因為Wrapper$InnerClass()是private的,不能由外部使用。因此編譯器不得不再生成一個可訪問的構造函數,由於這裡只有Wrapper類的private void testInnerClass()方法使用了new InnerClass(),所以編譯器只(需)為這個新的構造函數生成了Default-Access的訪問修改符。同時,為了和已有的缺省構造函數有所區別,就加入了一個Wrapper$1類型的參數,為此,編譯器還要生成一個Wrapper$1類。
為了更簡單,(也許)更清楚的看到編譯器生成的class代碼工作的原理,讀者可以使用java反編譯器,來看看class反編譯後生成的java源程序,下面是作者使用Jad反編譯後生成的Wrapper類的代碼:
// Decompiled by Jad v1.5.7d. Copyright 2000 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.Html
// Decompiler options: packimports(3)
// Source File Name: Wrapper.java
public class Wrapper
{
private class InnerClass
{
private InnerClass()
{
}
InnerClass(_cls1 _pcls1)
{
this();
}
}
public Wrapper()
{
}
private void testInnerClass()
{
InnerClass innerclass = new InnerClass(null);
}
public static void main(String args[])
{
Wrapper wrapper = new Wrapper();
wrapper.testInnerClass();
}
// Unreferenced inner classes:
/* anonymous class */
class _cls1
{
}
}
顯然,Wrapper$1類不會有任何實際的作用。