來自:碼農翻身(微訊號:coderising)
這是一個程式員的電腦硬碟,在一個叫做“學習”的目錄下曾經生活著兩個小程式,一個叫做Hello.java,即Java小子;另外一個叫做hello.c ,也就是C老頭兒。
C老頭兒的命運比較悲催,程式員主人覺得C語言的指標太複雜了,記憶體管理太難了,實在是學不會,就放棄了,順便把它給刪除了!
Java小子很懷念它,因為C老頭兒雖然老派,但知識淵博,教了他不少東西。
(註:參見文章《C老頭和Java小子的硬碟夜話》)
這天晚上,程式員心血來潮,決定跟Python混個臉熟,於是hello.py也入住了這個目錄。
經過了短暫的寒暄,摸清了對方的虛實,他倆便看對方不順眼了。
他倆都明白一山不容二虎的道理,如果不能把對方趕走,就難逃被主人刪除,去垃圾回收站的悲催命運。
想到這一層,Python變率先發難, 它皮笑又不笑地拍拍Java的肩膀:“Java 老弟….”
沒想到Java立刻反擊:“誰是你老弟?你得叫我Java 大哥。”
Python愣了一下:“難道你不知道我是1991年出生的,比你還大4歲?”
Java哼了一聲:“雖然比我大,那你混得也不怎麼樣啊?”
Python說:“10多年前我也許混得不咋地,也許不如你,可此一時彼一時,隨著人工智慧時代的到來,使用我的人越來越多了,不信你去看TIOBE排行榜,我的上升勢頭很猛烈啊。”
Java不屑地說:“切,增長到現在不還是老子一個零頭。”
Python 被激怒了,他決定先拿Java繁瑣的語法開刀,指著Java說:“看看你,一個HelloWorld都整得這麼麻煩,囉裡囉嗦。”
public class Hello
{
public static void main (String[] args)
{
System.out.println("Hello World!");
}
}
然後又指著自己說:“你看看我,多麼簡潔!”
print("Hello World!")
Java 默不作聲,其實心裡也挺羨慕。
“還有我開啟一個檔案多簡單,你行嗎?”
f = open("c: mpHello.java","r")
print(f.read())
f.close()
提到IO,Java心中就有莫名的痛,自己的IO模組設計得那麼優雅,可是人類為什麼就是不喜歡用呢?
他們老是說記不住到底該怎麼寫,看來是要改變下了。
看到Java 還是默不作聲,無法反擊,Python很得意,發揮宜將剩勇追窮寇的精神,抄起機關槍,繼續掃射:“看看我這個函式的預設值,你有嗎?”
class Employee():
def __init__(self, name , gender="male" , maritalStatus="single" ):
self.name = name
self.gender = gender
self.maritalStatus = maritalStatus
(友情提示:可左右滑動)
Java 一看到這段程式碼,立刻就來了精神:“你的self和我的this意思差不多,可是你為啥必須作為引數呢? 多醜陋啊!!還有這程式碼縮排,居然用空格,一不留神就出錯,真不知道你到底是怎麼想的。”
Python 沒想到Java這小子竟然從這個地方發起反擊, 一時語塞。
只聽到Java 問道:“有人說你Python的變數都沒有型別,是嗎?”
“胡說!我的變數怎麼沒有型別?我是動態語言,型別只會在執行時確定。”
var = 3
var = "hello world"
“你看看,這個變數var 第一次賦值,型別是個整數, 第二次就變成字串hello world了, 你小子做不到吧?”
Java笑而不語。
Python繼續說道:“由於我的動態特性,我可以輕鬆地實現Duck Typing:”
class Duck:
def help(self):
print( "Quaaaaaack! ")
class Person:
def help(self):
print( "help me!" )
def in_the_forest(x):
x.help()
in_the_forest(Duck())
in_the_forest(Person())
“看到沒有,這個Duck和Person並沒有實現共同的介面或者繼承相同的類,但是照樣可以作為引數傳遞給in_the_forest函式,是不是很靈活? 你應該是不行吧? 哈哈!” Python得意洋洋。
Java心裡明白,這的確是個很好的特性,寫起程式碼來非常爽快。
但他也不是吃素的, 一下子就抓住了命門: “寫起來很爽,讀起來就不爽了,我問你,假設人類看到了in_the_forest這個函式,他知道引數x的型別是什麼嗎?是Person? 是Bird? 還是別的類? ”
“還有,” Java繼續批判,“人類想重構一下Person函式的help方法,比如改成sos(self),你的IDE能安全地重構嗎?恐怕是不容易吧? 假設人肉重構改錯了,你也只能在執行時發現錯誤了!”
“動態一時爽,重構火葬場。” Java 冷冷地補了最後一刀。
由於自己是靜態型別,變數型別在編譯期就能確定,IDE那強大的智慧感知功能,自動安全重構的功能一直是引以為傲的賣點。
“怕啥,” Python假裝滿不在乎,“人類有單元測試做保證,再說了,我的程式碼緊湊得很,一行頂你十行,就是改起來也方便得多。”
雖然錶面滿不在乎,可Python已經暗暗心驚:一不小心被這小子帶坑裡去了,我得想辦法轉移陣地。
Java 開始組織防守反擊: “聽說過AOP沒有?啊? 聽說過,那你說說,你能不能實現AOP?”
Python 心裡偷著樂:這小子真是孤陋寡聞,總以為只有什麼Spring有AOP, 豈不知對於我們動態語言來說,實現AOP那簡直是易如反掌。
Python故意問道:“AOP無非就是對現有程式碼做增強,動態地新增一些安全,日誌,事務等‘切麵’功能,我知道你們Java 類,一旦被裝載就無法修改,那怎麼去實現程式碼的增強呢?”
Java得意地說:“我們可以在執行時生成新的類啊,讓新生成的類繼承老的類,或者和老的類實現同樣的介面,比如ASM這樣的工具,可以操作位元組碼去建立新的類,織入那些‘切麵’程式碼,這種工作如此精巧,讓人嘆為觀止。”
Python說道:“哈哈,我告訴你吧, 你那是不得已而為之,我們Python 就不同了,我們是動態語言,可以在執行時對一個類進行增強:新增方法,替換方法,根本不用操作那麼Low的位元組碼,我給你舉個簡單的例子:”
class Order:
def save(self):
print ("save order")
#把老的方法取用儲存起來
old_save=Order.save
#定義一個新方法,該新方法呼叫老方法
#併在方法前後加上了日誌
def save_with_logging(self):
print ("logging start")
old_save(self)
print ("logging end")
#把新方法賦值給Order類的save方法
Order.save=save_with_logging
#測試
t=Order()
t.save()
輸出:
logging start
save order
logging end
Java看著這段程式碼,瞠目結舌,心驚肉跳,一個類的方法在執行時竟然可以被替換掉! 實在是嚇人啊!在自己的世界中,這是想都不敢想的事情。
可是這不就輕鬆實現了對一個類的增強嗎? 也不用修改什麼位元組碼。
Python看到Java小子被鎮住了,繼續施壓: “我們Python想實現AOP,還可以使用裝飾器,Meta class等很多方式,我就不給你詳細講了。”
Java心裡還在想著那個被替換的函式, 看來在Python中, 函式就是一個物件,要不然怎麼能被替換掉? 既然是個物件,那肯定可以作為引數傳遞,也可以做為傳回值。 想想自己的Lambda運算式,本質上還是一個介面的實現,相當於帶著鐐銬在跳舞,心裡不由得嘆了口氣。
(註:參見《Lambda運算式有何用處?》)
看來我還得找出殺手鐧才能徹底將這個自大的Python小子給搞定,Java心想,可是他的動態語言確實是太靈活了,對了,虛擬機器! 我的虛擬機器發展了這麼多年,經受了業界最苛刻的考驗,效能強悍,在解釋執行位元組碼的過程中能發現那些“熱點”位元組碼,然後編譯成原生代碼執行,速度極快。 並且我的垃圾回收機制也極為完善。
Java把這個大殺器給拋了出來,Python的表情立刻就不對了,因為自己虛擬機器的效能確實不怎麼樣,但是Python非常狡猾,他立刻就把話題給轉移了:“現在的速度瓶頸不是CPU, 而是IO, 你知道網路和資料庫這倆貨有多慢嗎? 相對他們的速度,我們慢一點也沒關係……” Python成功地把兩個人拉到了同一個陣地中。
兩個傢伙你來我往,整整爭論了一夜,他們倆的聲音越來越大,吵得隔壁的“畢業設計.docx”怒氣衝衝地跑過來罵道:“到底還讓不讓老子睡覺了?!”
兩個人趕緊壓低聲音,繼續爭鬥,但誰也沒辦法徹底佔據上風,最後就覺得大家真是各有所長,只是適用範圍各不相同。
突然間,一道亮光照進來,把兩人的眼睛刺得生疼,原來天已大亮,主人開啟了這個檔案夾,選中了Hello.java和hello.py ,然後做了一個奇怪的操作。
Java 和Python 只覺得一陣頭暈目眩,轉瞬間就被拎到一個垃圾遍地的地方。
只見頭髮蓬亂的C老頭兒在一本叫做《C和指標》的電子書上坐著,目光獃滯地對他倆說:“你們好,歡迎來到回收站。看來主人又有了新歡,把你們倆也拋棄了。”
●編號416,輸入編號直達本文
●輸入m獲取文章目錄
Java程式設計
更多推薦:《18個技術類微信公眾號》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。