java中內部類種類較多,語法比較複雜,用法也不盡相同。
歸納下來,能夠分類爲如下五種內部類。java
本篇文章只對實際項目開發中用的較多的,普通內部類與匿名內部類作必定介紹。其餘三種如有興趣請自行經過谷歌或書籍進行了解。python
首先經過一個簡單的小示例,來看看內部類的語法吧。程序員
import java.util.HashMap;
public class Parcell {
private HashMap<String, String> testMap = new HashMap<String, String>();
class Contents {
// 返回一個外部類的引用.
public Parcell ParcellRef = Parcell.this;
}
class Destination {
public void putSomethingInMap() {
testMap.put("hello", "world");
System.out.println(testMap.get("hello"));
}
}
public Destination to() {
return new Destination();
}
public Contents contents() {
return new Contents();
}
public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination();
}
public static void main(String[] args) {
Parcell p = new Parcell();
Parcell.Contents c = p.contents();
Parcell.Destination d = p.to();
d.putSomethingInMap();
Parcell.Contents c1 = p.new Contents();
}
}
複製代碼
內部類的語法和相信你們都很熟悉。
在這裏我再自做主張的爲你們歸納一下編程
爲何static方法中須要p.new XXX()的方式而非static方法中咱們直接new 內部類名 就能夠建立一個對象了呢?
若是你有這樣的疑問請再看看第一條,必定能夠想明白的。設計模式
普通內部類的語法大體就是這樣了。
那麼,回到咱們主題。閉包
內部類到底有什麼用?咱們在實際項目中,應該如何使用內部類呢?
內部類的用處或者說用法,歸根結底,主要就是一點:
: 「內部類,主要是設計出來用來解決java中所‘缺乏’的,多重繼承的概念的。」ide
什麼?難道java不是靠接口來實現多重繼承的嗎?我認爲,這種說法對,也不對。下面咱們來看這樣一個例子。函數
你正在參與一項代號X的星際飛船項目。
宇航局的人但願飛船上的綜合機器人可以完成兩個工做。一是做爲嚮導,可以供人們查閱信息。二是做爲修理機器人,完成一些簡單的飛船平常維護工做。
做爲軟件工程師,你被要求編寫一段代碼來實現這兩個功能。ui
好消息是,嚮導部分的功能與飛船修理維護的功能,已經由你的同事們完成了!太好了,我只須要調用他們提供給咱們的接口就大功告成了!
壞消息是,同事們編寫的嚮導功能與飛船修理功能的接口,居然都叫作work!
這可傷腦筋了,應該怎麼辦呢?this
public class Guider {
public void work(String name) {
System.out.println("歡迎光臨" + name + ",請查閱飛船信息");
}
}
-------------------------------------------------------------------
public class Repairer {
public void work (String name) {
System.out.println("你好" + name + ",開始準備對飛船進行維護.");
}
}
-------------------------------------------------------------------
public class SpacecraftRobot extends Guider {
public void doGuidWork(String name) {
// 調用guider的work方法
work(name);
}
public void doRepairWork(String name) {
// 返回內部類引用,調用內部類實例的work方法。
new repairerRobot().doRepairWork(name);
}
public class repairerRobot extends Repairer {
public void doRepairWork(String name) {
work(name);
}
}
}
複製代碼
太棒了。經過使用內部類與「多重繼承」,咱們實現了這個功能。如今這個綜合機器人可以正常工做了!
對於用戶來講,只須要走到機器人面前,告訴機器人你想要doGuidWork仍是doRepairWork,它就可以幫你幹活兒了。內部類的代碼對用戶,對外界完全隱藏了起來,用戶惟一可以得到的信息就是這兩個方法而已。
綜合機器人原型機試作成功後,新的工做來了!
咱們須要對原型機進行量產。以知足每艘星際飛船的須要。
如今咱們要編寫一間生產綜合機器人的工廠。每當咱們訪問一次工廠,就可以從工廠中提取出一臺嶄新的綜合機器人。聰明的你想到了用工廠設計模式來解決這個問題!可是因爲有了內部類,因此咱們的工廠,稍稍顯得有點不一樣
// 機器人工廠接口。經過getSpaceCraftRobot方法對外提供機器人
public interface SpaceCraftRobotFactory {
SpacecraftRobot getSpaceCraftRobot();
}
-------------------------------------------------------------------
public class ProduceSpaceCraftRobot {
// 不再用顯示的建立工廠類的對象了!
private ProduceSpaceCraftRobot() {
}
// 經過匿名內部類,建立工廠對象!將工廠封裝到了內部。不對外界暴露
public static SpaceCraftRobotFactory produceRobot = new SpaceCraftRobotFactory () {
public SpacecraftRobot getSpaceCraftRobot() {
return new SpacecraftRobot();
}
};
}
-------------------------------------------------------------------
// 客戶
public class Consumer {
public static void main(String[] args) {
// 客戶來提取機器人了.
SpacecraftRobot x1 = ProduceSpaceCraftRobot.produceRobot.getSpaceCraftRobot();
x1.doGuidWork("lch");
x1.doRepairWork("lch");
}
}
複製代碼
經過建立匿名內部類,咱們使傳統的工廠設計模式優雅了許多!不再用在外部編寫new xxxFactory()這樣醜陋,多餘的代碼了。
如今的工廠被匿名內部類隱藏了起來。客戶只須要關心有沒有拿到趁心如意的機器人。不該該,不須要關心工廠的名字,也不須要知道工廠是幹嗎的。
真棒,你順利完成了宇航局交給你的任務。
恭喜你,你是這個星球的英雄。
做爲一個程序員,即便你歷來沒有使用過,你也應該據說過閉包與回調。
要從java,特別是j2ee的方向入手去講解閉包與回調,會比較困難。
因此咱們首先從python來入手,來了解閉包與回調究竟是什麼。
python是一門優秀的解釋性語言。你應該掌握他。
下面咱們來看一看,標準的回調,在Python中是什麼樣子的。
#定義一個返回sum函數的名叫base_sum函數的函數
def base_sum(a,b):
#在base_sum中定義一個sum()函數用來計算base_sum(a,b)的形參之合
def sum():
#返回a+b的值
return a + b
#返回定義的sum函數
return sum
#調用base_sum返回函數sum(),能夠理解爲返回了一個函數指針
return_method = base_sum(1,2)
#打印出返回的函數對象
print(return_method)
#經過指針回調函數對象,返回a與b的合
print(return_method())
----------
<function base_sum.<locals>.sum at 0x1018f3c80>
3
複製代碼
對於java程序員來講,在一個函數中定義另一個函數也許會比較燒腦。
你能夠試着這樣去理解他:
「首先你須要瞭解的是,函數也須要佔據內存空間,因此函數在內存中也是有地址的。在c語言中,函數名就表明這個函數的地址。
若是你有過c語言的編程經驗,你就應該知道在一個函數中,返回一個指針是一件很容易的事情。
因此,對於以上這段python代碼,你能夠嘗試把它理解爲:
base_sum()函數中定義了一個指向sum()函數的指針,而且這個指針做爲base_sum()的返回值。」
好了,如今咱們根據上面的例子,來「定義一下閉包」。
: 調用外部函數,返回一個持有外部函數變量,參數引用的內部函數對象的程序結構,咱們就稱它爲「閉包」。
遺憾的是,java中沒有爲咱們顯示的提供指針供咱們操做,也沒有提供相似python,javascrpit中的函數定義的語法,那麼咱們應該如何實現閉包呢?
不妨仍是經過綜合機器人來解答這個疑問吧。這一次,讓咱們稍稍修改一下綜合機器人的代碼以下:
public class SpacecraftRobot extends Guider {
// 外部類的成員變量
private String name;
public SpacecraftRobot(String name) {
this.name = name;
}
public class repairerRobot extends Repairer {
public void doRepairWork() {
// 內部類持有外部類的引用,訪問外部類的成員變量name。
work(name);
}
}
public void doGuidWork() {
// 調用guider的work方法
work(name);
}
public void doRepairWork() {
// 返回一個持有外部類變量引用的內部類的對象,而後調用這個對象,實現具體的業務邏輯.
new repairerRobot().doRepairWork();
}
}
複製代碼
經過對java內部類的合理利用,咱們「模擬」出了一個閉包的程序結構。
該程序經過調用外部類對象,從而返回了一個持有外部類對象變量引用的內部類對象。當咱們再次調用內部類對象的某個方法時,咱們實現了具體的業務邏輯。