程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> EffectiveJava——請不要在代碼中使用原生態類型,原生態類型

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

編輯:JAVA綜合教程

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


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

/**
 * 請不要在新代碼中使用原生態類型
 * @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還是會報錯的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved