Java的泛型——坑、優秀與缺陷
最近一直在寫一個自己的Android程序(https://github.com/renyuneyun/Easer),所以Java用得比較多。又由於我懶,所以總喜歡讓編譯器做更多,於是想到用泛型來解決之前存在的Object滿地飛又滿地強制類型轉換的情況。然而這時候卻發現,泛型只能解決其中一部分問題,另一部分問題依然存在。
於是起意記錄一下自己知道的、用過的以及碰到的東西,以期有人能給出更加的解決方案(或是乾脆直接指出我錯了最好。。。這樣解決起來最簡單)。
一般而言,Java的泛型可以讓程序員寫出一些“形式相同,但具體參數類型不同”的代碼。從字面上說,這一機制在許多語言中都有(如C++的模板),但由於各個語言的實現方式和語義取捨不同,導致具體支持的功能千差萬別。
本文主要集中於Java泛型機制中的坑爹之處。爲了介紹坑爹之處,於是也就需要涉及該機制的理解,同時也會簡單涉及其實現部分。當然,其中一些有意義的地方也會順帶提及(在做對比時)。
Qt中鏈接信號和槽的方法
最近又在用Qt寫東西,順便翻了翻Qt的文檔,發現鏈接信號和槽的方法有不少,Qt5和C++11的組合也帶來了一些不小變化。
所以有此一篇文章,對其稍加總結。
自記初習Qt
百無聊賴,於是就拿出Qt Creator來學一下Qt(C++)。若有錯誤,還望指正。
Qt使用標準的C++,只是加入了預處理器(moc)以及一些宏。這就意味着可以使用任意的C++編譯器來編譯Qt程序。
文件
Qt圖形界面程序一般有三個文件,通常狀態下後綴名爲:.ui、.h、.cpp。
.ui文件是界面的設計文件,本質是xml文件。在構建時會依據其產生一些源文件以進行編譯。
.h文件是標準的c++頭文件,內部包含各類聲明等內容。需要特別注意的是,如果要使用Qt的信號/槽機制,需要在類聲明代碼塊首部分加入Q_OBJECT宏。
.cpp文件顯然是普通的C++程序源代碼。
從預設的組織結構看,Qt中的.h文件中僅僅寫聲明,定義在相應的.cpp文件中書寫。這點看起來比微軟的VS中那些亂七八糟的強許多。
然而打開進行編譯的臨時目錄,其中依據.ui文件自動生成的.h文件中卻包含了一些定義。不過這似乎是有意爲之,而且沒有直接暴露在編程者面前,也算是很不錯的做法。
信號/槽
相傳Qt最引以爲傲的就是它的“信號/槽”機制。該機制是一個解耦程度極高的組件通信方案,允許組件間在互不相知的狀態下進行通信。
如名稱所示,“信號”表示發送消息的部分,“槽”表示接收消息的部分。當一個信號發出時,其相關聯的槽會被立即(實際上仍有極其微小的延遲)調用。
信號或者槽連同它的參數類型表,一起被稱爲其“簽名”,意即其標識。Qt通過簽名類辨識信號或槽,也通過簽名來判斷一個信號是否能和槽相關聯。事實上,一個信號可和多個槽對應,一個槽也可和多個信號對應,甚至信號也可以引發另一個信號,這也就爲編程帶來了極大的靈活性。
爲了便於編程,Qt已對其組件(例如PushButton)定義好了一些信號(例如“按下”),編程時可直接使用。
信號
信號是一個不需要定義的函數。它應當在類中聲明,並在代碼中被引發。
聲明信號,只需在類聲明中寫入
signals: void 信號名( 參數類型表 );
槽
除了聲明方法不同以及槽可以用於信號/槽機制通信外,槽的一切均和普通函數一致。
聲明槽,應當在類聲明中加入:
訪問方式 slots: 返回值類型 槽名( 參數表 );
之後在相應的.cpp文件中定義即可。
其中訪問方式可爲public、protected、private中任一種,並會導致槽的作用域不同(和C++標準概念中一致)。
關聯信號和槽
關聯信號和槽的通常做法是
connect(發送者, SIGNAL(信號(參數類型表)), 接受者/*即槽所在*/, SLOT(槽(參數類型表)));
其中SIGNAL和SLOT均爲宏,其參數中實際上要寫的是信號或者槽的簽名。之前說過,我們可以將一個信號和另一個信號關聯起來,這只需將上面的槽換成信號即可。
其中信號的參數可以比槽的多,多餘的部分在槽被激活(調用)時會被忽略掉。
實際上,關聯信號與槽的方法還有一些變體,具體可參考我的這篇文章。
解除信號和槽的關聯
解除信號和槽的關聯需要用到disconnect函數,其使用方法和connect幾乎一致:
disconnect(發送者, SIGNAL(信號(參數類型表)), 接受者, SLOT(槽(參數類型表)));
實際上,該函數中除了發送者外,其餘部分均可以填“0”,表示“任意”。
手動發送信號
有時候Qt自帶的信號無法滿足我們的需求,這時候我們就需要知道如何手動發送自己定義的信號。
手動發送信號,只需要在想要發送信號的地方使用emit關鍵字發送你的信號:
emit 信號( 參數 );
實際上,emit是一個宏,並且其內容爲空。這也就意味着完全可以不使用emit來發送一個信號。但是個人推薦使用emit來明確標識這是一個信號。