Java內部類超詳細總結(含程式碼示例)
- 2019 年 10 月 3 日
- 筆記
什麼是內部類
什麼是內部類?
顧名思義,就是將一個類的定義放在另一個類的內部。
概念很清楚,感覺很簡單,其實關鍵在於這個內部類放置的位置,可以是一個類的作用域範圍、一個方法的或是一個程式碼塊的作用域範圍。
所以理解了概念只是第一步,掌握細節才能徹底搞定Java的內部類特性。
看例子,這是最普通的內部類:
public class Product1 { class Design{ private String name = "P30 pro"; public String showName() { return name; } } class Content{ private int i; Content(int value){ i = value; } int value() {return i;} } public void show(int value) { Content c = new Content(value); Design d = new Design(); System.out.println(d.showName()); System.out.println(c.value()); } public static void main(String[] args) { Product1 p = new Product1(); p.show(6000); } }
說明:
上面這個示例展示了內部類最基礎的用法,就是將一個或多個類的定義放在了外圍內的內部。可以看到在show()方法中的使用和普通類一樣,沒有區別。
另外,在外圍類的非靜態方法之外的任意位置,不能通過直接new 內部類的方式創建內部類對象。會報編譯錯誤。
像這樣:
還有這樣:
如果想要在外圍類非靜態方法之外創建內部類對象。怎麼辦呢?
正確的姿勢是這樣子:
在外圍類中增加兩個公共方法,返回內部類的引用。
public Design design() { return new Design(); } public Content content(int value) { return new Content(value); }
然後通過外部類對象調用方法的方式獲取內部類對象。
public static void main(String[] args) { Product2 p = new Product2(); p.show(6000); Product2.Content c1 = p.content(100); Product2.Design d1 = p.design(); }
值得注意的是,外部類之外的其他類,也是不能直接訪問到該外部類的內部類對象的。
會報編譯錯誤。這也符合內部類的定義,就是為外圍類服務的嘛!
內部類的特性
1.可以鏈接到外部類
當生成一個內部類對象時,此對象與製造它的外圍對象之間就有了一種聯繫,所以它能訪問外圍對象的所有成員,而不需要任何特殊的條件。
下面的例子是《Java編程思想》中的示例
首先定義一個Selector介面
public interface Selector { boolean end(); Object current(); void next(); }
然後定義一個Sequence類,其中定義有一個private的內部類。
public class Sequence { private Object[] items; private int next = 0; public Sequence(int size) {items = new Object[size];} public void add(Object x) { if(next < items.length) { items[next++] = x; } } private class SequenceSelector implements Selector{ private int i = 0; public boolean end() { return i == items.length; } public Object current() { return items[i]; } public void next() { if(i < items.length) {i++;} } } public Selector selector() { return new SequenceSelector(); } public static void main(String[] args) { Sequence sequence = new Sequence(10); for(int i = 0; i < 10; i++) { sequence.add(Integer.toString(i)); } Selector selector = sequence.selector(); while(!selector.end()) { System.out.print(selector.current() + " "); selector.next(); } } }
說明:
可以看到SequenceSelector是一個內部類,其end()、current()和next()都用到了外圍類中private的items欄位。
2.使用.this和.new
.this的用法
如果需要生成對外部類對象的引用,可以使用外部類的名字後面緊跟圓點和this。
如下所示:
public class DotThis { void name() {System.out.println("name");} public class Inner{ public DotThis outer() { return DotThis.this; } } public Inner inner() {return new Inner();} public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner inner = dt.inner(); inner.outer().name(); } }
需要注意DotThis.this只是產生了正確的外部類引用。並沒有創建外部類對象。
.new的用法
可以通過該語法創建內部類對象,不過要注意的是要使用外部類的對象去創建。
public class DotNew { public class Inner{} public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dnInner = dn.new Inner(); } }
內部類分類
1、局部內部類
定義在一個方法中或是方法中某一作用域內的類。稱作局部內部類。
public class Product3 { public Section section(String inputName) { class ASection implements Section{ private String name; private ASection(String name) { this.name = name; } @Override public String hello() { return name + " say hello"; } } return new ASection(inputName); } public static void main(String[] args) { Product3 p = new Product3(); Section section = p.section("aaaaa"); System.out.println(section.hello()); } }
ASection是一個Section介面的實現,Section介面程式碼如下:
public interface Section { String hello(); }
說明:
- 該內部類在section()方法中,該方法之外不能訪問ASection類;
- 方法內部類不允許使用訪問許可權修飾符(public、private、protected);
- 注意方法返回的是Section 的引用,即有向上轉型。
另外還可以將內部類的定義放在方法中某一語句塊中,如if語句塊中。
public class Product4 { public String check(boolean flag) { String checkId = null; if(flag) { class DetailCheck{ private String id; private DetailCheck(String id) { this.id = id; } String getId() { return id; } } DetailCheck dc = new DetailCheck("1111"); checkId = dc.getId(); } return checkId; } public static void main(String[] args) { Product4 p = new Product4(); System.out.println(p.check(true)); } }
說明:
DetailCheck內部類在if語句塊中,因此它的作用範圍也在if語句塊的範圍之內。超出該範圍是不可用的。比如這樣就會編譯報錯:
2、匿名內部類
匿名內部類其實是一種特殊的方法內部類(局部內部類)。它特殊在於將內部類的定義和其對象創建結合在了一塊。沒有通過class關鍵字顯示聲明內部類名稱,故謂之「匿名」。
看程式碼示例:
public class Product5 { public Section section() { return new Section() { private String name = "hayli"; @Override public String hello() { // TODO Auto-generated method stub return name + " haha"; } }; } public static void main(String[] args) { Product5 p = new Product5(); p.section(); } }
說明:
此處Section可以是介面,也可是基類。
3、嵌套類(靜態內部類)
使用static關鍵字修飾的內部類,叫做靜態內部類,也稱作嵌套類。
嵌套類和普通內部類之間最大的區別是:
- 普通內部類對象隱式地保存了一個引用,指向創建它的外部類對象。而嵌套類創建對象,並不需要外部類對象。
- 不能從嵌套類的對象中訪問非靜態的外部類對象。
- 普通內部類不能有static數據和static欄位,也不能包含嵌套類,但是嵌套類可以包含所有這些東西。
public class Product6 { private static int id = 100; private static class BSection implements Section{ private String name = "bbbb"; @Override public String hello() { return name + " hello"; } // 只能訪問外部類的靜態數據或欄位 public int getId() {return id;} // 可以包含靜態數據或方法 static int x = 200; public static void test1() {} // 可以再嵌套一層 static class BInner{ private String name; static void test1() {System.out.println("inner ===");} } } public static void main(String[] args) { Section section = new BSection(); section.hello(); }
總結
本篇介紹了什麼是內部類、內部類最普通定義方法和Java內部類的幾種具體類型詳解。雖然工作中使用內部類的機會不會,但是了解這些最基礎的知識,真的在項目中遇到內部類的寫法,也能看懂是怎麼回事了。
掃碼關注微信公眾號:二營長的筆記。回復「二營長」,可領取Java相關技術資料。