sort - java arraylist中文




將ArrayList<String>轉換為String[] array (4)

這個問題在這裡已經有了答案:

我正在android環境中工作,並嘗試了下面的代碼,但它似乎並沒有工作。

String [] stockArr = (String[]) stock_list.toArray();

如果我定義如下:

String [] stockArr = {"hello", "world"};

有用。 有什麼我失踪了嗎?


Java 8中的另一種選擇:

String[] strings = list.stream().toArray(String[]::new);

我可以看到許多答案顯示如何解決問題,但只有斯蒂芬的答案試圖解釋為什麼會出現問題,所以我會嘗試在此主題上添加更多內容。 這是一個關於為什麼Object[] toArray沒有改變為T[] toArray可能原因的故事,其中泛型引入了Java。

為什麼String[] stockArr = (String[]) stock_list.toArray(); 不會工作?

在Java中, 泛型類型僅在編譯時存在 。 在運行時,關於泛型類型的信息(如你的情況<String> )將被刪除,並替換為Object類型(看看類型擦除 )。 這就是為什麼在運行時toArray()不知道用什麼精確類型來創建新數組,因此它使用Object作為最安全的類型,因為每個類都擴展Object,因此它可以安全地存儲任何類的實例。

現在問題是你不能將Object[]實例轉換為String[]

為什麼? 看看這個例子(讓我們假設class B extends A ):

//B extends A
A a = new A();
B b = (B)a;

儘管這樣的代碼會被編譯,但在運行時我們會看到拋出ClassCastException因為由引用a持有的實例實際上並不是B類型(或其子類型)。 為什麼這個問題(為什麼這個異常需要被轉換)? 其中一個原因是B可能擁有A沒有的新方法/字段,所以有可能有人會嘗試通過b引用使用這些新成員,即使持有的實例沒有(不支持)它們。 換句話說,我們最終可能會嘗試使用不存在的數據,這可能會導致很多問題。 所以為了防止這種情況,JVM會拋出異常,並停止進一步潛在的危險代碼。

你現在可以問“為什麼我們甚至不能更早停下來?為什麼涉及這種轉換的代碼甚至是可編譯的?編譯器不應該停止它嗎?”。 答案是:否,因為編譯器無法確定引用所持有的實例的實際類型是什麼,並且有可能存在將支持b引用的接口的類B實例。 看看這個例子:

A a = new B(); 
      //  ^------ Here reference "a" holds instance of type B
B b = (B)a;    // so now casting is safe, now JVM is sure that `b` reference can 
               // safely access all members of B class

現在讓我們回到你的數組。 正如您所看到的,我們無法將Object[]數組的實例轉換為更精確的類型String[]

Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown

這裡的問題有點不同。 現在我們確信String[]數組不會有其他字段或方法,因為每個數組只支持:

  • []運營商,
  • length提交,
  • 從Object超類型繼承的方法,

所以它不是數組接口,這是不可能的。 問題是Strings旁邊的Object[]數組可能會存儲任何對象 (例如Integers ),所以有可能一個美好的一天我們最終會嘗試調用方法strArray[i].substring(1,3)沒有這種方法的Integer

所以要確保這種情況永遠不會發生,Java數組引用只能保持

  • 與參考相同類型的數組的實例(引用String[] strArr可以包含String[]
  • 子類型數組的實例( Object[]可以保存String[]因為StringObject子類型),

但不能保持

  • 來自reference( String[]的數組類型的超類型數組不能包含Object[]
  • 與引用類型無關的類型數組( Integer[]不能包含String[]

換句話說,這樣的事情是可以的

Object[] arr = new String[] { "ab", "cd" }; //OK - because
               //  ^^^^^^^^                  `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as 
                                //     reference

你可以說解決這個問題的一種方法是在運行時找到所有列表元素之間的最常見類型並創建該類型的數組,但是這種方式在列表的所有元素都是通用類型的一種類型的情況下不起作用。 看一看

//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());

現在最常見的類型是B ,而不是A所以toArray()

A[] arr = elements.toArray();

會返回Bnew B[]數組。 這個數組的問題是編譯器允許你通過添加new A()元素來編輯它的內容,但是你會得到ArrayStoreException因為B[]數組只能包含類B或其子類的元素,以確保所有元素將支持B接口,但A實例可能沒有B所有方法/字段。 所以這個解決方案並不完美。

這個問題的最佳解決方案是通過將此類型作為方法參數傳遞來明確地告訴返回什麼類型的數組toArray()

String[] arr = list.toArray(new String[list.size()]);

要么

String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.

嘗試這個

String[] arr = list.toArray(new String[list.size()]);

正確的做法是:

String[] stockArr = stock_list.toArray(new String[stock_list.size()]);

我想在這裡添加其他很好的答案,並解釋如何使用Javadoc來回答你的問題。

toArray() (無參數)的Javadoc here 。 正如你所看到的,這個方法返回一個Object[]不是 String[] ,它是你列表運行時類型的數組:

public Object[] toArray()

返回包含此集合中所有元素的數組。 如果集合對其迭代器返回的元素的順序做出任何保證,則此方法必須以相同順序返回元素。 返回的數組將保持“安全”,因為集合不會引用它。 (換句話說,即使集合由Array支持,該方法也必須分配新的數組)。 調用者可以自由修改返回的數組。

然而,在該方法下面,是toArray(T[] a) 的Javadoc 。 正如你所看到的,這個方法返回一個T[] ,其中T是你傳入的數組的類型。起初這看起來像你在找什麼,但是你不清楚為什麼你要傳入一個數組你加入它,僅用於類型等)。 該文檔清楚地表明,傳遞數組的目的主要是定義要返回的數組類型(這正是您的用例):

public <T> T[] toArray(T[] a)

返回包含此集合中所有元素的數組; 返回數組的運行時類型是指定數組的運行時類型。 如果集合適合指定的數組,則將其返回。 否則,將使用指定數組的運行時類型和此集合的大小分配一個新數組。 如果集合符合指定數組並且有空餘空間(即,數組的元素多於集合的元素),則緊跟在集合結尾之後的數組中的元素將設置為null。 僅當調用者知道集合不包含任何空元素時,這對於確定集合的長度非常有用。)

如果此集合對其迭代器返回的元素的順序做出任何保證,則此方法必須以相同順序返回元素。

這個實現檢查數組是否足夠大以包含集合; 如果不是,它會分配一個正確大小和類型的新數組(使用反射)。 然後,它遍歷集合,將每個對象引用存儲在數組的下一個連續元素中,從元素0開始。如果數組大於集合,則在集合結束後將空值存儲在第一個位置。

當然,要真正理解這兩種方法之間的區別,需要了解泛型(如其他答案中所述)。 然而,如果你第一次去Javadocs,你通常會找到你的答案,然後親自看看你還需要學習什麼(如果你真的這麼做)。

還要注意,在這裡閱讀Javadocs有助於你理解你傳入的數組結構應該是什麼。 雖然它實際上可能並不重要,但不應該像這樣傳遞一個空數組:

String [] stockArr = stockList.toArray(new String[0]);  

因為從doc開始,這個實現檢查數組是否足夠大以包含集合; 如果不是,它會分配一個正確大小和類型的新數組(使用反射)。 當您可以輕鬆傳遞大小時,不需要額外的開銷來創建新的數組。

通常情況下,Javadocs為您提供了豐富的信息和方向。

嘿,等一下,有什麼反映?





arraylist