為什么在C#中inner class不能夠訪問(wèn)外部類的非靜態(tài)成員,如下面的一段代碼就存在這樣的問(wèn)題:
public class TestOuter
{
public static void outer(){}
public void outer2(){}
internal class A
{
public voidtest()
{
outer(); // 可以調(diào)用外部靜態(tài)方法,無(wú)法調(diào)用實(shí)例方法
outer2(); // 本句無(wú)法通過(guò)編譯
}
}
}
在Java中,下面的代碼是可以很正常的使用的:
public class testinner
{
static public void Main(String[] args)
{
testinner tester = new testinner();
testinner.Inner inner = tester.new Inner();
inner.testinner();
}
public void test(){ }
class Inner
{
public void testinner()
{
test();
}
}
}
對(duì)比之下,C#中的內(nèi)部類能夠使用外部類定義的類型和靜態(tài)方法,但是不能直接使用外部類的實(shí)例方法,直接看來(lái),外部類對(duì)于內(nèi)部類的作用更像是一個(gè)命名空間,在C#中,始終可以用(只要訪問(wèn)控制允許)
TestOuter.A instance = new TestOuter.A();
來(lái)創(chuàng)建一個(gè)內(nèi)部類的實(shí)例,這個(gè)實(shí)例與外部類的任何實(shí)例沒(méi)有任何直接的關(guān)系。類似于Java中的靜態(tài)內(nèi)部類。
Java中,非靜態(tài)內(nèi)部類可以訪問(wèn)所有外部類的方法和變量。所以Java中的內(nèi)部類的構(gòu)造也依賴于外部類,必須使用如:
Outer.Inner inner = outer.new Inner();
這樣的語(yǔ)法來(lái)定義內(nèi)部類的實(shí)例以確保他與某一確定的外部類的對(duì)象相對(duì)應(yīng)。
而在C#中,類區(qū)分為Nested Class和Not-Nested Class,前者是聲明在其他數(shù)據(jù)類型內(nèi)部的類。后者是直接定義在某一個(gè)命名空間的類。
非內(nèi)嵌類只允許使用public和internal的訪問(wèn)控制,而內(nèi)置類則允許使用所有的五種訪問(wèn)控制符,private, protected , internal protected。內(nèi)部類也可以訪問(wèn)外部類的所有方法,包括instance方法和private方法,但是需要顯式的傳遞一個(gè)外部類的實(shí)例。
如:
public class TestOuter
{
public void outer2(){}
internal class A
{
public A(TestOuter obj)
{
Outer_this = obj
}
public void test()
{
obj.outer2();
}
TestOuter Outer_this;
}
}
C#這樣做的原因,主要是為了避免outer.new 這樣的語(yǔ)法,保持一致的對(duì)象創(chuàng)建方式。雖然相比于Java需要?jiǎng)?chuàng)建一個(gè)新的方法和變量,但是對(duì)象的創(chuàng)建過(guò)程更加直接,而且避免了隱含的內(nèi)部類與外部類的實(shí)例之間的關(guān)系。
如果分析到CLR的實(shí)現(xiàn)層面,我們也可以知道,C#的內(nèi)部類應(yīng)該并沒(méi)有包含外部類的虛函數(shù)表,而僅僅包含了靜態(tài)方法表,所有對(duì)外部類的方法的調(diào)用時(shí)通過(guò)外部類指針作的。具體的機(jī)制可能更復(fù)雜。但是除此以外,內(nèi)部類并沒(méi)有被作為一種特殊的類型處理,而是必須與其他普通的對(duì)象采取一樣的機(jī)制進(jìn)行創(chuàng)建。
C#的內(nèi)部類提供了覆蓋的功能,在一個(gè)包含了內(nèi)部類的類的子類中可以用關(guān)鍵字new 來(lái)覆蓋同名內(nèi)部類的實(shí)現(xiàn)。
如:
class A1
{
class B1 { }
}
class A2 : A1
{
new class B1 { }
}
C#中的內(nèi)部類會(huì)覆蓋同名的外部類的方法。如果上面的A1中定義任何名為B1()的方法,該方法將被覆蓋。
內(nèi)部類使用的一些General Information:
創(chuàng)建內(nèi)部類的一個(gè)目的是為了抽象外部類的某一狀態(tài)下的行為,或者內(nèi)部類僅在外部類的某一特定上下文存在。或是隱藏實(shí)現(xiàn),通過(guò)將內(nèi)部類設(shè)為private,可以設(shè)置僅有外部類可以訪問(wèn)該類。內(nèi)部類的另外一個(gè)重要的用途是當(dāng)外部類需要作為某個(gè)特定的類工作,而外部類已經(jīng)繼承與另外一個(gè)類的時(shí)候,因?yàn)镴ava不支持多繼承,所以創(chuàng)建一個(gè)對(duì)應(yīng)的內(nèi)部類作為外部類的一個(gè)façade來(lái)使用。
通常,創(chuàng)建內(nèi)部類的動(dòng)機(jī)都是上面中的其中之一或者幾項(xiàng)。而其中最常見(jiàn)的目的莫過(guò)于前兩項(xiàng)。
我們看一下Java中處理事件的代碼:
public class Demo1 extends JPanel
{
class IconDemo implements Icon {}
}
這個(gè)例子對(duì)應(yīng)了上面的第一種動(dòng)機(jī),即封裝特定狀態(tài)或特定實(shí)現(xiàn)的動(dòng)機(jī)。IconDemo僅在的Demo1中使用,對(duì)應(yīng)特定的圖標(biāo)繪制行為。
常見(jiàn)的另外一個(gè)場(chǎng)合是需要自定義Action的行為,我們可能有如下的類:
public class Demo1 extends JPanel implements ActionListener
{
private JMenuItem item1;
void foo()
{
Item1 = new JMenuItem(“test” , new TestAction(“some action”));
}
Private TestAction extends AbstractAction
{
//code goes here
}
}
這種情況下,TestAction可以看成是一種特化的要求。
隱藏實(shí)現(xiàn)的需求往往對(duì)應(yīng)于內(nèi)部抽象,或者二次抽象(Secondary Abstraction),它對(duì)應(yīng)著對(duì)于類內(nèi)部的部分行為進(jìn)一步抽象,聚簇。常見(jiàn)的一種情況是在內(nèi)部類中創(chuàng)建私有的結(jié)構(gòu),用于抽象盡在類的內(nèi)部使用的數(shù)據(jù)結(jié)構(gòu)。
而作為Façade使用的情況相當(dāng)于外部類作為內(nèi)部類的創(chuàng)建工廠,當(dāng)外部請(qǐng)求需要外部類提供一個(gè)它不能夠繼承的基類或接口的時(shí)候,外部類產(chǎn)生一個(gè)內(nèi)部類的實(shí)例對(duì)象,返回給相應(yīng)的請(qǐng)求。
創(chuàng)建內(nèi)部類的一些原則:
如果一下一些情況出現(xiàn),避免使用內(nèi)部類:
內(nèi)部類的功能過(guò)分膨脹影響了對(duì)外部類的閱讀
內(nèi)部類內(nèi)部包含內(nèi)部類,對(duì)代碼的可讀性影響很大
內(nèi)部類可以不依賴于外部類被使用,在這種情況下,說(shuō)明內(nèi)部類與外部類的抽象沒(méi)有包含關(guān)系,則應(yīng)該將內(nèi)部類作為一種獨(dú)立的抽象設(shè)計(jì)為另外一個(gè)外部類。(可以參考內(nèi)部類設(shè)計(jì)的第二目的,內(nèi)部抽象)
注:在VC中可以使用內(nèi)部類作為模版的局部特化處理,掠過(guò)不提。其實(shí)我也不太懂,:)
public class TestOuter
{
public static void outer(){}
public void outer2(){}
internal class A
{
public voidtest()
{
outer(); // 可以調(diào)用外部靜態(tài)方法,無(wú)法調(diào)用實(shí)例方法
outer2(); // 本句無(wú)法通過(guò)編譯
}
}
}
在Java中,下面的代碼是可以很正常的使用的:
public class testinner
{
static public void Main(String[] args)
{
testinner tester = new testinner();
testinner.Inner inner = tester.new Inner();
inner.testinner();
}
public void test(){ }
class Inner
{
public void testinner()
{
test();
}
}
}
對(duì)比之下,C#中的內(nèi)部類能夠使用外部類定義的類型和靜態(tài)方法,但是不能直接使用外部類的實(shí)例方法,直接看來(lái),外部類對(duì)于內(nèi)部類的作用更像是一個(gè)命名空間,在C#中,始終可以用(只要訪問(wèn)控制允許)
TestOuter.A instance = new TestOuter.A();
來(lái)創(chuàng)建一個(gè)內(nèi)部類的實(shí)例,這個(gè)實(shí)例與外部類的任何實(shí)例沒(méi)有任何直接的關(guān)系。類似于Java中的靜態(tài)內(nèi)部類。
Java中,非靜態(tài)內(nèi)部類可以訪問(wèn)所有外部類的方法和變量。所以Java中的內(nèi)部類的構(gòu)造也依賴于外部類,必須使用如:
Outer.Inner inner = outer.new Inner();
這樣的語(yǔ)法來(lái)定義內(nèi)部類的實(shí)例以確保他與某一確定的外部類的對(duì)象相對(duì)應(yīng)。
而在C#中,類區(qū)分為Nested Class和Not-Nested Class,前者是聲明在其他數(shù)據(jù)類型內(nèi)部的類。后者是直接定義在某一個(gè)命名空間的類。
非內(nèi)嵌類只允許使用public和internal的訪問(wèn)控制,而內(nèi)置類則允許使用所有的五種訪問(wèn)控制符,private, protected , internal protected。內(nèi)部類也可以訪問(wèn)外部類的所有方法,包括instance方法和private方法,但是需要顯式的傳遞一個(gè)外部類的實(shí)例。
如:
public class TestOuter
{
public void outer2(){}
internal class A
{
public A(TestOuter obj)
{
Outer_this = obj
}
public void test()
{
obj.outer2();
}
TestOuter Outer_this;
}
}
C#這樣做的原因,主要是為了避免outer.new 這樣的語(yǔ)法,保持一致的對(duì)象創(chuàng)建方式。雖然相比于Java需要?jiǎng)?chuàng)建一個(gè)新的方法和變量,但是對(duì)象的創(chuàng)建過(guò)程更加直接,而且避免了隱含的內(nèi)部類與外部類的實(shí)例之間的關(guān)系。
如果分析到CLR的實(shí)現(xiàn)層面,我們也可以知道,C#的內(nèi)部類應(yīng)該并沒(méi)有包含外部類的虛函數(shù)表,而僅僅包含了靜態(tài)方法表,所有對(duì)外部類的方法的調(diào)用時(shí)通過(guò)外部類指針作的。具體的機(jī)制可能更復(fù)雜。但是除此以外,內(nèi)部類并沒(méi)有被作為一種特殊的類型處理,而是必須與其他普通的對(duì)象采取一樣的機(jī)制進(jìn)行創(chuàng)建。
C#的內(nèi)部類提供了覆蓋的功能,在一個(gè)包含了內(nèi)部類的類的子類中可以用關(guān)鍵字new 來(lái)覆蓋同名內(nèi)部類的實(shí)現(xiàn)。
如:
class A1
{
class B1 { }
}
class A2 : A1
{
new class B1 { }
}
C#中的內(nèi)部類會(huì)覆蓋同名的外部類的方法。如果上面的A1中定義任何名為B1()的方法,該方法將被覆蓋。
內(nèi)部類使用的一些General Information:
創(chuàng)建內(nèi)部類的一個(gè)目的是為了抽象外部類的某一狀態(tài)下的行為,或者內(nèi)部類僅在外部類的某一特定上下文存在。或是隱藏實(shí)現(xiàn),通過(guò)將內(nèi)部類設(shè)為private,可以設(shè)置僅有外部類可以訪問(wèn)該類。內(nèi)部類的另外一個(gè)重要的用途是當(dāng)外部類需要作為某個(gè)特定的類工作,而外部類已經(jīng)繼承與另外一個(gè)類的時(shí)候,因?yàn)镴ava不支持多繼承,所以創(chuàng)建一個(gè)對(duì)應(yīng)的內(nèi)部類作為外部類的一個(gè)façade來(lái)使用。
通常,創(chuàng)建內(nèi)部類的動(dòng)機(jī)都是上面中的其中之一或者幾項(xiàng)。而其中最常見(jiàn)的目的莫過(guò)于前兩項(xiàng)。
我們看一下Java中處理事件的代碼:
public class Demo1 extends JPanel
{
class IconDemo implements Icon {}
}
這個(gè)例子對(duì)應(yīng)了上面的第一種動(dòng)機(jī),即封裝特定狀態(tài)或特定實(shí)現(xiàn)的動(dòng)機(jī)。IconDemo僅在的Demo1中使用,對(duì)應(yīng)特定的圖標(biāo)繪制行為。
常見(jiàn)的另外一個(gè)場(chǎng)合是需要自定義Action的行為,我們可能有如下的類:
public class Demo1 extends JPanel implements ActionListener
{
private JMenuItem item1;
void foo()
{
Item1 = new JMenuItem(“test” , new TestAction(“some action”));
}
Private TestAction extends AbstractAction
{
//code goes here
}
}
這種情況下,TestAction可以看成是一種特化的要求。
隱藏實(shí)現(xiàn)的需求往往對(duì)應(yīng)于內(nèi)部抽象,或者二次抽象(Secondary Abstraction),它對(duì)應(yīng)著對(duì)于類內(nèi)部的部分行為進(jìn)一步抽象,聚簇。常見(jiàn)的一種情況是在內(nèi)部類中創(chuàng)建私有的結(jié)構(gòu),用于抽象盡在類的內(nèi)部使用的數(shù)據(jù)結(jié)構(gòu)。
而作為Façade使用的情況相當(dāng)于外部類作為內(nèi)部類的創(chuàng)建工廠,當(dāng)外部請(qǐng)求需要外部類提供一個(gè)它不能夠繼承的基類或接口的時(shí)候,外部類產(chǎn)生一個(gè)內(nèi)部類的實(shí)例對(duì)象,返回給相應(yīng)的請(qǐng)求。
創(chuàng)建內(nèi)部類的一些原則:
如果一下一些情況出現(xiàn),避免使用內(nèi)部類:
內(nèi)部類的功能過(guò)分膨脹影響了對(duì)外部類的閱讀
內(nèi)部類內(nèi)部包含內(nèi)部類,對(duì)代碼的可讀性影響很大
內(nèi)部類可以不依賴于外部類被使用,在這種情況下,說(shuō)明內(nèi)部類與外部類的抽象沒(méi)有包含關(guān)系,則應(yīng)該將內(nèi)部類作為一種獨(dú)立的抽象設(shè)計(jì)為另外一個(gè)外部類。(可以參考內(nèi)部類設(shè)計(jì)的第二目的,內(nèi)部抽象)
注:在VC中可以使用內(nèi)部類作為模版的局部特化處理,掠過(guò)不提。其實(shí)我也不太懂,:)