1995年,網景瀏覽器第一次加載Java Applet時,沒人想到這套生命周期會活成"技術活化石"。
4個方法、4個階段、零個main函數——這是Java史上最另類的程序入口。
Payal Mehra在Day 57的學習筆記里,把Applet生命周期拆解得像一份解剖報告。但這份報告背后,藏著一段瀏覽器戰爭的殘骸。
init():只活一次的"出生證明"
Applet被瀏覽器加載時,init()是第一個被觸發的鉤子。它只做一件事:初始化。
沒有命令行參數,沒有標準輸入輸出。你的代碼跑在瀏覽器的沙盒里,像被關進透明玻璃房的實驗動物——能看見外面,但觸碰不到。
Mehra的示例代碼里,init()只打印了一行字符串。真實的90年代,這里塞滿了圖像加載、參數解析、網絡連接請求。那時候沒有npm install,程序員得手動把依賴塞進幾十KB的jar包里。
瀏覽器調用init()的時機很微妙:頁面解析到標簽時立即執行,不管用戶有沒有滾動到那個位置。這導致了一個經典bug——頁面還沒顯示,Applet已經開始吃內存。
start()與stop():瀏覽器標簽頁的"心跳監測"
這是Applet最聰明的設計,也是最被低估的設計。
用戶切換到別的標簽頁,stop()自動觸發;切回來,start()重新喚醒。瀏覽器成了操作系統的調度器,而Applet是第一個響應這種調度機制的客戶端技術。
Mehra的代碼示例里,這兩個方法各打印一行狀態。但想想這個場景:1998年,一個股票行情Applet在后臺暫停,釋放CPU給前臺的游戲;用戶切回來,數據流無縫續接。
這種"生命周期感知"的能力,Flash抄了,Silverlight抄了,連現代PWA的Page Visibility API都是同源思路。區別在于,Applet在25年前就寫進了規范。
destroy():資源回收的"臨終關懷"
瀏覽器決定卸載Applet時,destroy()是最后的機會。釋放文件句柄、關閉網絡連接、清理線程——做晚了,內存泄漏;做早了,用戶可能只是誤關標簽頁。
Mehra的示例里,destroy()同樣只是一行打印。但真實的生產環境,這里是bug的重災區。Applet跑在瀏覽器的進程里,但擁有自己的線程。瀏覽器關閉時,線程不會自動消失。
Sun Microsystems的文檔里反復警告:不要在destroy()里做阻塞操作。但程序員能聽進去多少?2000年代的崩潰報告里,"Applet未響應"占了相當大的比例。
paint():被生命周期遺忘的"編外人員"
Mehra的代碼里有個細節:paint(Graphics g)不屬于四個標準階段,但每個Applet都必須實現它。
這是Applet的UI層入口。瀏覽器窗口需要重繪時——無論是首次顯示、被遮擋后恢復、還是用戶調整窗口大小——paint()被調用。它像餐廳里的傳菜員,不屬于廚房團隊,但缺了它,菜到不了桌上。
Graphics對象由瀏覽器傳入,綁定到具體的屏幕區域。這種"被動渲染"模式,和游戲引擎的主循環截然不同。Applet從不主動問"現在該畫了嗎",它只能等瀏覽器敲門。
這套機制在2017年徹底死亡。
Java 9標記Applet為廢棄,Java 11正式移除。瀏覽器這邊,Chrome 45(2015年)砍掉NPAPI支持,Firefox 52(2017年)跟進。Mehra現在學習Applet,相當于醫學生解剖渡渡鳥——了解進化史,但別指望臨床應用。
不過,生命周期的設計思想還活著。Android的Activity回調(onCreate/onStart/onStop/onDestroy)、iOS的UIViewController、甚至React的useEffect清理函數,都是同一套模式的變體。瀏覽器標簽頁即應用生命周期,這個隱喻從未過時。
Mehra的學習筆記最后埋了個問題:如果當年瀏覽器廠商和Sun談攏了安全沙盒的標準,Applet會不會活成另一種形態?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.