天天看點

探讨Java内部類的可見性

在Java中,當生成一個内部類的對象時,此對象與制造它的外部類通過外部類的.this保持着聯系,是以該内部類對象可以通路其外部類對象的所有成員,包括private成員。

而該内部類對象對于其他類的對象的通路,遵照正常的通路權限文法,這一點也沒有什麼特别支援。這裡需要探讨的是,外部類以及其他類的對象可以如何通路到某個内部類對象,即内部類的可見性問題。

下面是一個示例程式Out.java,其中包含了4個不同通路權限的内部類(private,default,protected,public),在每個内部類中,分别包含4個不同通路權限的成員與方法。在外部類Out中提供了得到内部類執行個體的方法。

Out.java

<b>package</b> com.zj.main;

<b>public</b> <b>class</b> Out {

    <b>public</b> PrivateIn getPrivateIn(){

       <b>return</b> <b>new</b> PrivateIn();

    }

    <b>public</b> DefaultIn getDefaultIn(){

       <b>return</b> <b>new</b> DefaultIn();

    <b>public</b> ProtectedIn getProtectedIn(){

       <b>return</b> <b>new</b> ProtectedIn();

    <b>public</b> PublicIn getPublicIn(){

       <b>return</b> <b>new</b> PublicIn();

    <b>private</b> <b>class</b> PrivateIn <b>implements</b> InMethod{

       <b>private</b> <b>int</b> private_arg;

       <b>int</b> default_arg;

       <b>protected</b> <b>int</b> protected_arg;

       <b>public</b> <b>int</b> public_arg;

       <b>private</b> <b>void</b> private_method(){};

       <b>void</b> default_method(){};

       <b>protected</b> <b>void</b> protected_method(){};

       <b>public</b> <b>void</b> public_method(){};

    <b>class</b> DefaultIn <b>implements</b> InMethod{

    <b>protected</b> <b>class</b> ProtectedIn <b>implements</b> InMethod{

    <b>public</b> <b>class</b> PublicIn <b>implements</b> InMethod{

    <b>public</b> <b>static</b> <b>void</b> main(String[] args){

       //create an outer object

       Out out=<b>new</b> Out();

       //create a private inner object by 'new'

       Out.PrivateIn privateIn=out.<b>new</b> PrivateIn();

       privateIn.private_arg=0;

       privateIn.private_method();

       // create a private inner object  by 'out's method'

       Out.PrivateIn privateIn2 = out.getPrivateIn();

       privateIn2.private_arg = 0;

       privateIn2.private_method();

}

所有的4個内部類都實作了一個接口InMethod,該接口的作用在下文中會有讨論。下面先讨論内部類所在的外部類對其内部類對象的通路權限問題。

<b>1.</b><b>外部類的通路</b><b></b>

<b></b>

我們通過兩種兩種方式試圖建立内部類的執行個體。

方式一 OuterClassName.InnerClassName inner=new Ouer().new Inner();

通過外部類對象.new 的方式,可以得到private inner class 的執行個體,并且可以通路它的private成員和private方法。自然default、protected和public的都可以通路。

方式二 通過外部類方法get InnerInstance()

此種方法也可以通路所有内部類的所有成員和方法。

是以,一個内部類的對象對生成它的外部類對象是完全可見的,包括private内部類、private成員與private方法。

<b>2.</b><b>同包其他類的通路</b><b></b>

下面,在同一個包内建立一個SamePackage.java類,試圖通路Out類的所有内部類。

SamePackage.java

<b>public</b> <b>class</b> SamePackage {

    <b>public</b> <b>static</b> <b>void</b> main(String[] args) {

       // create an outer object

       Out out = <b>new</b> Out();

       //Out.PrivateIn privateIn=out.new PrivateIn();

       //-&gt;error: Out.PrivateIn is not visible.

       // create a default inner object by 'new'

       Out.DefaultIn defaultIn = out.<b>new</b> DefaultIn();

       //defaultIn.private_arg=0;-&gt;error:not visible

       defaultIn.default_arg = 0;

       //defaultIn.private_method();-&gt;error:not visible

       defaultIn.default_method();

       // create a private inner object by 'out's method'

       //Out.PrivateIn privateIn2 = out.getPrivateIn();

       //-&gt;error:Out.PrivateIn is not visible through out.getPrivateIn() is visible.

       // create a private inner object by 'out's method',

       // but use Interface reference to handle it

       InMethod privateIn=out.getPrivateIn();

       privateIn.public_method();

使用方式一試圖得到private 内部類失敗,根本得不到内部類的句柄。

//create a private inner object by 'new'

//Out.PrivateIn privateIn=out.new PrivateIn();

//-&gt;error: Out.PrivateIn is not visible.

    但是可以正常的通路default通路權限的内部類的對象。當然是通路不到它的private成員和private方法的。自然protected和public的都可以通路。

雖然可以調用外部類對象的getInnerInstance()方法,但由于得不到private内部類的句柄,是以此種方法無法建立private内部類的執行個體。

// create a private inner object by 'out's method'

//Out.PrivateIn privateIn2 = out.getPrivateIn();

//-&gt;error:Out.PrivateIn is not visible through out.getPrivateIn() is visible.

但由于所有的内部類都實作了接口InMethod。

&lt;&lt;interface&gt;&gt; InMethod.java

<b>public</b> <b>interface</b> InMethod {

    <b>void</b> public_method();

是以還是可以通過接口的引用通路到private内部類的public方法。自然default、protected和public的都可以通路這個public方法。

// create a private inner object by 'out's method',

// but use Interface reference to handle it

InMethod privateIn=out.getPrivateIn();

privateIn.public_method();

<b>3.</b><b>不同包其他類的通路</b><b></b>

在另一個包中建立一個類DifferPackage.java。

DifferPackage.java

<b>package</b> com.zj.other;

<b>import</b> com.zj.main.InMethod;

<b>import</b> com.zj.main.Out;

<b>public</b> <b>class</b> DifferPackage {

       //create a public inner object by 'new'

       Out.PublicIn publicIn=out.<b>new</b> PublicIn();

       publicIn.public_arg=0;

       publicIn.public_method();

       // create a public inner object by 'out's method'

       Out.PublicIn publicIn2 = out.getPublicIn();

       publicIn2.public_arg=0;

       publicIn2.public_method();

       //use Interface reference

       InMethod method;

       method=out.getPrivateIn();

       method.public_method();

       method=out.getDefaultIn();

       method=out.getProtectedIn();

       method=out.getPublicIn();

通過new方式和getInnerInstance()方法隻能通路public内部類的public成員和public方法;如果使用接口的引用,則可以通路所有4個内部類的public方法。

<b>4.</b><b>不同包繼承類的通路</b><b></b>

在另一個包中建立一個類DifferPackageExtend.java,它繼承自外部類Out。

DifferPackageExtend.java

<b>public</b> <b>class</b> DifferPackageAndExtend <b>extends</b> Out{

       //create an DifferPackageAndExtend's object,which extends Out

       Out extend=<b>new</b> DifferPackageAndExtend();

       //create a protected inner object by 'new'

       //Out.ProtectedIn protectedIn=extend.new ProtectedIn();

       //-&gt;error:The constructor Out.ProtectedIn() is not visible

       // create a protected inner object by 'out's method'

       Out.ProtectedIn protectedIn=extend.getProtectedIn();

       protectedIn.public_arg=0;

       protectedIn.public_method();

通過new方式,雖然可以得到内部類的句柄Out.ProtectedIn,但該内部類的構造子卻不可見。

通過getInnerInstance()方法得到protected内部類的對象,但隻能通路到public成員和public方法。由此可知,protected内部類并不關心是否有其他類繼承自它的外部類。所有protected通路權限不在此種情況下适用。

本文轉自zhangjunhd51CTO部落格,原文連結:http://blog.51cto.com/zhangjunhd/65624,如需轉載請自行聯系原作者