2013-01-06 108 views
5

我有下面的代碼片段,這工作正常。不應該拋出編譯時錯誤,因爲我已經將c定義爲ArrayList,它將包含String對象,但我添加了Integer對象。那麼爲什麼它不會拋出編譯時間/運行時錯誤?用泛型聲明的這個集合沒有錯誤?

Collection c = new ArrayList<String>(); 
c.add(123); 

我知道下面會拋出編譯時錯誤,但爲什麼不在上面。這兩個代碼片段之間的邏輯區別是什麼?

Collection<String>() c = new ArrayList(); 
c.add(123); 
+0

第一個應該給''rawtypes''警告。注意編譯器。保持你的代碼免費是個好主意。 –

回答

6

第一代碼段不會導致編譯時間錯誤,因爲在該行

c.add(123) 

編譯器檢查C的類型。由於您將宣稱爲 c爲Collection,因此編譯器會如此處理。由於Collection提供了一種方法add(Object),所以對c的任何對象,尤其是整數,都是完全合理的。請注意,如果您嘗試將集合值讀回爲字符串,則此程序將會產生運行時錯誤

在您的第二個代碼片段中,您提供了編譯器使用的更多信息。在這段代碼中,它知道它處理的CollectionCollection<String>,它只能接受Strings。因此,沒有方法add(int)add(Object),只有add(String)。這會導致編譯時錯誤。

+0

OP的第一個代碼片段運行良好;除非您嘗試將'Integer'作爲'String'讀取,否則不會有運行時錯誤。 –

+0

@Alexander沒有任何運行時錯誤,理想情況下它應該? – emilly

+0

我原以爲會有一個,但根據@ OliCharlesworth對他自己的回答的評論,似乎並沒有。我寧願有一個,但顯然Java不這麼認爲:) –

3

爲什麼它沒有拋出編譯時錯誤?

因爲它不是語法上或語義上無效的,所以它是不明智的。

請注意,大多數現代IDE(例如Eclipse)都可以配置爲警告您未參數化的Collection c,並且可能無法編譯。

+0

那麼奧利它應該給運行時錯誤比因爲我已經聲明ArrayList應該包含字符串對象,但我正在添加整數對象。但它也沒有給出任何運行時錯誤。爲什麼這樣? – emilly

+2

@ emilly:因爲泛型在運行時不存在;他們*擦除*。因此,在運行時,所有集合的行爲就好像它們是原始的(未參數化的)。 –

+0

然後做新的ArrayList沒有好處()對不對?實際上,在元素類型的右邊顯示集合是一種無用的異常抑制警告 – emilly

0

在第一個示例中,集合是「原始」。這通常會導致警告但不是錯誤(取決於您的確切設置)。這是爲了能夠編譯所有Java 5之前的遺留代碼。

第二個示例中,您將「原始」對象分配給參數化版本,只能通過顯式轉換完成。

+0

理想情況下,它應該導致運行時錯誤但它沒有拋出:( – emilly

0

1)什麼是邏輯差異?

上圖:集合可以聲明爲不帶泛型類型。這被稱爲raw type。該集合可以保存任何類型的集合。由於使用原始類型集合,在運行時可能將字符串集合用作導致運行時異常的整數集合,編譯器通常會引發警告。由於您沒有在上面的例子中輸入集合,因此編譯器無法防止這些運行時異常。如果你知道它的用途並知道你在做什麼,該警告可以忽略。

下圖:但是聲明爲集合的變量<字符串>不能容納任何種類的集合。它必須是 String類型的集合。它是強類型的。編譯器將此視爲錯誤是正確的。

2)爲什麼上面的代碼片段不會導致編譯器錯誤?

Java是strong typed,它確保type safety。上面的代碼片段不是類型安全的,但是Java允許。這可能是由於歷史原因:泛型只在Java 1.5中引入,所以如果上面的代碼片段會導致編譯錯誤,那麼大多數Java 1.4代碼將在Java 1.5編譯器中被破壞。

並非所有的編程語言都以這種向後兼容的方式演變(例如PHP)。在引入Java 1.5時,顯然向後兼容性被重視的是類型安全。

相關問題