2017-08-10 54 views
2

爲什麼在Java中可能會出現以下情況?爲什麼有可能新增一個接口陣列

Integer[] ints = (Integer[])new Comparable[10]; 

但它在運行時得到ClassCastException。什麼是new接口的數組的用例。

+0

java在運行時識別類型。鑄造不能隱藏真實的類型。 –

+2

'Integer'是一個「Comparable」,但「Comparable」不一定是「Integer」。 – Mena

+0

這不是創建接口的實例,而是創建一個實現接口的類。 –

回答

1

對於這種情況:你有一個接口和實現接口的兩個(或更多)類:

interface MyInterface 
{ 
    public void someMethod(); 
} 

class MyClass1 implements MyInterface 
{ 
    public void someMethod() { System.out.println("foo");} 
} 

class MyClass2 implements MyInterface 
{ 
    public void someMethod() { System.out.println("bar");} 
} 

你這樣稱呼它:

public static void main(String[] args) 
{ 
    MyInterface[] array = new MyInterface[2]; 
    array[0] = new MyClass1(); 
    array[1] = new MyClass2(); 

    array[0].someMethod(); 
    array[1].someMethod(); 
} 

接口的數組爲您提供了在陣列中保存該接口的不同實現的方法

+1

請解釋downvote嗎?我弄錯了什麼嗎? – ParkerHalo

6

要回答具體問題:

Comparable toComplare[] = new Comparable[10]; 

爲什麼不創建一個數組,允許您存儲任何實現了Comparable接口的對象?

的觀點是:接口表示「常用功能」 - 這可能有助於看看從「視圖」對象。

當然,該陣列中存儲的對象總是有一些「真實」類 - 但所有這些對象都將實現接口提供的功能。

所以你可以做這樣的事情:

toCompare[0] = new Integer(5); 
toCompare[1] = new BigDecimal("3.2"); 
... 

我並不是說這是東西,你會經常使用,但說的 - 它可以讓你「收集」的對象在一定的,具體的「觀察「他們的能力。這也是值得指出的是:具有這樣的陣列做意味着你將能夠做到:

toCompare[0].compareTo(toCompare[1]); 

成功!

除此之外:一個轉換總是暗示你,程序員知道編譯器不知道的東西。所以編譯器退後一步,讓你做到這一點 - 假設你知道你在做什麼。但是,因爲你在問題中顯示的代碼顯然是而不是是正確的,所以在運行時真實回來咬你。是的,可以在編譯時決定給定的代碼是不正確的。

+0

在這種特殊情況下,靜態分析器可能會在編譯時標記它。 – Thilo

+0

@Thilo正確;我又增加了一個關於這個的話。編譯器在這裏沒有抱怨的事實可能是這個問題最有趣的方面。 – GhostCat

+1

編譯器無法按照語言規範拒絕它。 (但它可能會發出警告,我們已經看到越來越多的這些年來被添加) – Thilo

1

Integer實施Comparable,並不意味着Integer[] implements Comparable[],所以你不能轉換不同類型的數組。但是,您可以將Integer放入Comparable[]數組的元素中。

+0

這是錯誤的。你可以絕對地將'Integer []'賦值給'Comparable []'。這編譯和運行得很好:'Comparable [] x = new Integer [10];' – Thilo

+0

這與我寫的完全相反。試試這個'Integer [] ints =(Integer [])new Comparable [] {1};',你將會收到'Exception in thread'main「java.lang.ClassCastException:[Ljava.lang.Comparable;不能轉換爲[Ljava.lang.Integer;' – partlov

+0

你寫了''Integer []'沒有實現'Comparable []'「。這是錯誤的。每個'Integer []'也是一個'Comparable []'。 – Thilo

1

編譯器查看右側的類型,並看到它是一個數組Comparable。一般來說,它可能Integer[](因爲它可以指定爲Comparable[])。

我們知道它不會是Integer[],因爲右邊的表達式是一個構造函數調用。但編譯器看起來並不那麼遠。它使用相同的邏輯,就好像該表達式是一個聲明類型爲Comparable[]的方法調用。它沒有看清楚實際的類型。

所以編譯器會接受你的類型轉換,因爲它可能可能成功。它只會拒絕根本無法工作的演員(根據聲明的類型),例如鑄造IntegerString

請注意,它可能是一個設計缺陷,允許在數組中的這種協變量。您可以將Integer[]投射到Comparable[],但這有問題,因此您的不能List<Integer>List<Comparable>

0
  1. 原因ClassCastException是由於堆污染。 這裏尋找更多細節http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ050
  2. new使用情況的接口陣列/只接口與任何類對象,工具該接口(或)給出匿名內部類定義來填補它。
+0

數組無法發生堆污染,因爲它們在運行時檢查組件類型(它不會像使用泛型集合一樣被擦除)。如果您嘗試輸入不好的東西,則會得到ArrayStoreExceptions。 – Thilo

0

這是因爲要執行縮小引用轉換

類整數實現可比接口:

public final class Integer extends Number implements Comparable<Integer> 

見:5.1.6. Narrowing Reference Conversion

從任何數組類型SC []與任何陣列類型TC []相關,前提條件是SC和TC是參考類型,而re是從SC到TC的縮小參考轉換。

此類轉換需要在運行時進行測試,以確定實際參考值是否爲新類型的合法值。如果不是,則引發ClassCastException。

相關問題