上篇文章--筆記19簡要介紹了成員內部類、局部內部類和匿名內部類,下麵對成員內部類再補充一些內容。 主要有以下6點: 1.成員內部類不可以有靜態成員,成員變數為static final時除外 2.外部類不可以直接訪問成員內部類的成員變數或調用成員內部類的成員方法 3.成員內部類可以無限制的訪問外部類 ...
上篇文章--筆記19簡要介紹了成員內部類、局部內部類和匿名內部類,下麵對成員內部類再補充一些內容。
主要有以下6點:
1.成員內部類不可以有靜態成員,成員變數為static final時除外
2.外部類不可以直接訪問成員內部類的成員變數或調用成員內部類的成員方法
3.成員內部類可以無限制的訪問外部類的成員變數、調用外部類的成員方法
4.成員內部類的成員與外部類成員同名時,內部類成員會屏蔽外部類的同名成員
5.成員內部類本身可以由訪問許可權修飾符修飾
6.成員內部類的成員變數和成員方法也可以由訪問許可權修飾符修飾
(註:時間有點晚了,5、6條下篇再寫吧)
作者: 蟬蟬
請尊重作者勞動成果,轉載請在標題註明“轉載”字樣,並標明原文鏈接:
http://www.cnblogs.com/chanchan/p/8254124.html
下麵分別展開說明:
1.成員內部類不可以有靜態成員,成員變數為static final除外
示例:
1 //筆記19:內部類--成員內部類--不能有靜態成員,成員變數為static final時除外 2 class InnerClass { 3 String name = "li"; 4 String inname; 5 static String ingender = "female"; 6 7 //不能有靜態成員,除非聲明為static final 8 void testStFi() { 9 System.out.println("ingender:" + ingender); 10 } 11 12 //不能有靜態成員方法 13 static void testStFiMeth() { 14 System.out.println("成員內部類的靜態成員方法"); 15 } 16 } 17 18 public static void main(String[] args) { 19 20 Person per = new Person(); 21 Person.InnerClass inC = per.new InnerClass(); 22 23 //筆記19:內部類--成員內部類--4不能有靜態成員,除非聲明為static final 24 inC.testStFi(); 25 }
編譯時會報出下麵的錯誤:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The field ingender cannot be declared static in a non-static inner type, unless initialized with a constant expression
The method testStFiMeth cannot be declared static; static methods can only be declared in a static or top level type
分析:
(1).根據錯誤提示,成員內部類不能有靜態成員變數,除非該成員由常量表達式初始化;
大家知道,由static final修飾的成員變數其值不可改變,是編譯時常量,所以把
static String ingender = "female";
改為:
static final String ingender = "female";
再編譯就可以通過了。
(2).成員內部類為什麼不可以有靜態成員變數呢?
1).對於外部類來說,當類尚未載入時,訪問靜態成員變數或創建一個對象都可以引起類的載入,而類載入時就會為靜態成員變數分配空間。訪問其靜態成員變數時,如果類尚未載入,則會先載入類,併為靜態成員變數分配空間,然後就可以訪問了;如果類已經載入過了,說明靜態成員變數已經分配過記憶體了,直接訪問就可以了。所以,外部類不論什麼情況下都可以正確的訪問其靜態成員變數。(參考筆記11)
2).而對於成員內部類來說,外部類載入時,並不會被自動載入;只有外部類的一個對象在首次創建成員內部類的對象時,才會引起成員內部類的載入。假設成員內部類有靜態成員變數,如果在成員內部類載入之前就需要訪問其靜態成員變數呢?很顯然,在類載入之前,其靜態成員變數是未分配記憶體的,這時候要訪問的是一個並不存在的變數,就會出錯。所以,成員內部類是不能有靜態成員變數及靜態成員方法的(道理類似)。
參考圖片更直觀:
(3).延伸:外部類與成員內部類的載入方式和父類與子類之間的載入方式是不一樣的
1).成員內部類與外部類是附屬與被附屬的關係,必須通過外部類對象來創建成員內部類的對象,所以可以先載入外部類,等需要的時候再載入成員內部類。且一個外部類對象可以創建多個內部類對象,是一對多的關係。最近每天睡覺前小姑娘都要聽“泥娃娃”,“泥娃娃,泥娃娃,一個泥娃娃,一樣的眉毛,一樣的眼睛,眼睛不會眨...”。泥娃娃像人一樣,但又比人少了點什麼,就把人看成外部類,泥娃娃就是人的成員內部類,哈哈,人創造了泥娃娃,而且可以創造多種多樣的泥娃娃。
2).而子類與父類是is-a的關係,兩個類相互獨立,但可以看成子類對象里隱含了一個父類對象。首次使用子類時,要先載入父類併為其靜態成員變數分配記憶體,再載入子類併為其靜態成員變數分配記憶體,然後依次初始化成員變數,調用構造方法等等(可參考筆記11)。所以這裡父類子、類都要載入。
幾者的關係見下圖:
2.外部類不可以直接訪問成員內部類的成員變數或調用成員內部類的成員方法
示例:
類Person中定義了一個成員內部類InnerClass,Person的成員方法outerCAccessinC訪問InnerClass的成員變數inname。
1 //成員內部類 2 class InnerClass { 3 String name = "li"; 4 String inname; 5 6 void printInC() { 7 System.out.println("inner class"); 8 } 9 } 10 11 //筆記19:內部類--成員內部類--外部類能訪問內部類成員變數、調用成員方法嗎? 12 public void outerCAccessinC() { 13 System.out.println("inname:" + inname); 14 } 15 16 public static void main(String[] args) { 17 18 Person per = new Person(); 19 20 //筆記19:內部類--成員內部類--外部類不能訪問內部類成員變數或調用成員方法 21 per.outerCAccessinC(); 22 per.printInC(); 23 }
結果出現下述錯誤:
第13行提示如下的錯誤:
inname cannot be resolved to a variable
22行提示如下的錯誤:
The method printInC() is undefined for the type Person
這說明外部類是無法直接訪問成員內部類的成員變數或成員方法的。
反面來看,假如外部類可以直接訪問成員內部類的成員,還以上面的程式為例,創建一個Person類對象per,per調用方法outerCAccessinC,由於這時尚未創建成員內部類的對象,其成員變數當然也沒有分配空間,這時per將訪問一個不存在的變數inname,這是不允許的。
所以成員內部類的成員對外部類是不可見的,外部類是無法直接訪問成員內部類的成員的。
3.成員內部類可以無限制訪問外部類的成員變數及調用外部類的成員方法
示例:
類Person定義了若幹個成員變數及一個成員內部類InnerClass。成員內部類InnerClass中定義了成員方法testVarMeth,testVarMeth訪問及調用了外部類Person的多個成員變數和成員方法。
String name; int age; String gender; public String education; //防問許可權修飾符 private String hobby; protected String residence; static String citizenship = "Chinese"; class InnerClass { void testVarMeth() { System.out.println("name:" + name); System.out.println("education:" + education); System.out.println("hobby:" + hobby); System.out.println("residence:" + residence); System.out.println("citizenship:" + citizenship); System.out.println("age:" + getAge()); System.out.println("gender:" + getGender()); } } public static void main(String[] args) { Person per = new Person(); Person.InnerClass inC = per.new InnerClass(); //筆記19:內部類--成員內部類--內部類訪問外部類成員變數、調用成員方法 inC.testVarMeth(); }
輸出結果為:
name:null education:null hobby:null residence:null citizenship:Chinese age:0 gender:null
從結果可以看出,成員內部類可以隨意訪問或調用外部類的成員變數或成員方法,與訪問許可權及類型等都沒有關係。
4.成員內部類的成員與外部類成員同名時,內部類成員會屏蔽外部類的同名成員
示例:
對2中的程式稍加修改,為成員內部類InnerClass添加一個與Person同名的成員變數name:
String name = "li";
再執行程式的話,輸出結果變為:
name:li education:null hobby:null residence:null citizenship:Chinese age:0 gender:null
可以看出,如果成員內部類與外部類有同名的成員的話,成員內部類內部會屏蔽掉外部類的同名成員,也即,外部類的同名成員對成員內部類是不可見的。