EffectiveJava——請不要在代碼中使用原生態類型

来源:http://www.cnblogs.com/babycomeon/archive/2016/06/22/5598697.html
-Advertisement-
Play Games

先看一個慄子,看看能不能找出來裡面的錯誤: 運行一下,看一下報錯結果: 對的,是一個ClassCastException,這是一個編譯器聲稱的轉換,因此一般會保證成功,但是我嘛在這個慄子中忽略了一條編譯器的警告,就會為此而付出代價。 但是,如果用unsafeAdd(List<Object> list ...


  先看一個慄子,看看能不能找出來裡面的錯誤:

/**
 * 請不要在新代碼中使用原生態類型
 * @author weishiyao
 *
 */
public class Test {
	
	public static void main(String[] args) {
		List<String> strings = new ArrayList<>();
		unsafeAdd(strings, new Integer(42));
		String string = strings.get(0);
		System.out.println(string);
	}
	
	private static void unsafeAdd(List list, Object object) {
		list.add(object);
	}
}

  運行一下,看一下報錯結果:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	at com.weishiyao.effectiveJava.entry23.Test.main(Test.java:16)

  對的,是一個ClassCastException,這是一個編譯器聲稱的轉換,因此一般會保證成功,但是我嘛在這個慄子中忽略了一條編譯器的警告,就會為此而付出代價。

  但是,如果用unsafeAdd(List<Object> list, Object object)代替原生的List類型,我們的IDE會直接報錯。

  在不確定或者不在乎集合中元素類型的情況下,你也許會使用原生態的類型。例如,假設想要編寫一個方法,它有兩個集合(set),並從中返回他們公有的元素的數量。如果不熟悉範型的話,可以參考以下方式來編寫這種方法:

	static int numElementsInCommen(Set s1, Set s2) {
		int result = 0;
		for (Object object : s1) {
			if (s2.contains(object)) {
				result++;
			}
		}
		return result;
	}

  這個方法倒是可行,但是它使用了原生態類型,這是很危險的。從java1.5發行版本開始,java就提供了一種安全的替代方法,稱作無限制的通配符類型,如果要使用範型,但是確定或者不關心實際的參數類型,就可以用一個問號代替。例如範型Set<E>的無限制通配符類型為Set<?>。這是最普通的參數化Set類型,可以持有任何集合。

  在無限制通配類型Set<?>和原生態類型Set之間有什麼區別呢?這個問號真正起到作用了麽?這一點不需要贅述,但通配符類型是安全的,原生態類型則不安全。可以將任何元素放入使用原生態類型的集合中,因此很容易破壞該集合類型的約束條件;但不能將任何元素(除了null)放到Collection<?>中。

  不要在新代碼中使用原生態類型,這條規則有兩個小小的例外,兩者都源於“範型信息可以在運行時被擦除”這一事實。在類文字中必須使用原生形態規範不允許使用參數化類型。換句話說,List.class,String[].class和int.class都是合法的。但是List<String>.class和List<?>則不合法。

  這條規則第二個例外與instanceof操作符有關。由於範型信息可以在運行時被擦除,一次在參數化類型而非無限制通配符上使用instanceof操作符時非法的。用無限制通配符類型代替原生態類型,對instanceof操作符的行為不回產生任何影響。在這種情況下,尖括弧<>和問號?就顯得多餘了。下麵是利用範型來使用instanceof操作符的首選方法:

				if (object instanceof Set) {	// Raw type
					Set<?> m = (Set<?>) object;	// Wildcard type
				}

  註意,一旦確定這個object是個Set,就必須將他轉換成通配符類型Set<?>,而不是原生類型,這個是受檢的,否則的話我們的IDE還是會報錯的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言 大多數系統裡面好像都有獲取消息的功能,但這些消息來源都不是實時的,比如你開兩個瀏覽器,用兩個不同的賬號登錄,用一個賬號給另外一個賬號發送消息,然而並不會實時收到消息,必須要自己手動F5刷新一下頁面才會顯示自己的消息,這樣感覺用戶體驗不太好。之前看了Learning hard關於Signal ...
  • 原文地址:http://docode.top/Article/Detail/10002 目錄: 1、Http協議上傳文件(以圖片為例)請求報文體內容格式 2、完整版HttpWebRequest模擬上傳文件請求報文內容封裝 3、asp.net(c#)使用HttpWebRequest攜帶請求參數模擬上傳 ...
  • 前言 用過Lucene.net的都知道,我們自己搭建索引伺服器時和解決搜索匹配度的問題都用到過盤古分詞。其中包含一個詞典。 那麼既然用到了這種國際化的框架,那麼就避免不了中文分詞。尤其是國內特殊行業比較多。比如油田系統從勘探、打井、投產等若幹環節都涉及一些專業辭彙。 再像電商,手機、手機配件、筆記本 ...
  • Arigis for WPF 標繪 箭頭 ArcGISPlotSilverlightAPI ...
  • 至2002微軟公司推出.NET平臺已近15年,在互聯網快速迭代的浪潮中,許多語言已被淘汰,同時也有更多新的語言涌現,但 .Net 依然堅挺的站在系統開發平臺的一線陣營中 ...
  • 先給大家介紹一個開源工具Sigar 官網:http://sigar.hyperic.com/ API: http://www.hyperic.com/support/docs/sigar/index-all.html(由於是英文的,英文不好的可以用谷歌瀏覽器的翻譯功能,直接轉換為簡體中文進行閱讀) ...
  • 1、python的moudles文件中__all__作用 Python的moudle是很重要的一個概念,我看到好多人寫的moudle里都有一個__init__.py文件。有的__init__.py中是空白,有的卻會有__all__參數。搜索了下總結下__all__參數的作用。 如果其他頁面impor ...
  • 一、線程 多任務可以由多進程完成,也可以由一個進程內的多線程完成,一個進程內的所有線程,共用同一塊記憶體python中創建線程比較簡單,導入threading模塊,下麵來看一下代碼中如何創建多線程。 主線程從上到下執行,創建5個子線程,列印出'start',然後等待子線程執行完結束,如果想讓線程要一個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...