W języku Java ArrayList<E>
Podstawa implementacji na tablicy obiektów.
Czy ktoś może mi wyjaśnić, dlaczego implementacja ArrayList<E>
używa tablicy Object[]
do przechowywania danych zamiast E[]
? Jaką korzyść z używania Object[]
?Dlaczego implementacja ArrayList korzysta z Object []?
Odpowiedz
W języku Java tworzenie tablicy typu ogólnego nie jest proste.
Prosta podejście nie kompiluje:
public class Container<E> {
E[] arr = new E[3]; // ERROR: Cannot create a generic array of E
}
Wymień E
z Object
, i wszystko jest dobrze (kosztem dodatkowej złożoności gdzie indziej w realizacji pojemnika).
Istnieją alternatywne podejścia, ale przedstawiają inny zestaw kompromisów. Dla obszernej dyskusji, patrz How to create a generic array in Java?
Zważywszy type erasure (czyli fakt, że parametry takie jak rodzajowych typu E
W przykładzie są usuwane w rodzaju kompilacji), podejrzewam, że wygenerowany kod bajtowy byłby podobny w obu przypadkach.
Z punktu widzenia konserwacji, użycie parametru typu zamiast obiektu spowodowałoby łatwiejsze odczytanie kodu (ponieważ ograniczyłoby liczbę rzutów). Ale ponieważ API z ArrayList
nigdy nie eksponuje tej "surowej" tablicy Object
, to chyba nie ma to znaczenia dla nas zwykłych programistów Javy :)
Po pierwsze, zdaj sobie sprawę, że rzeczywisty typ środowiska wykonawczego obiektu tablicy musi być Object[]
. Dzieje się tak dlatego, że tablice znają swoje typy komponentów w środowisku wykonawczym (różne typy tablic są faktycznie różnymi typami w środowisku wykonawczym), a zatem trzeba określić typ komponentu podczas tworzenia tablicy, ale obiekt ArrayList
nie zna jego argumentu typu w czasie wykonywania.
Powiedział, że typ kompilacji zmiennej instancji mogłoby zostać uznane jako albo Object[]
lub E[]
, z różnymi wadami i zaletami:
Jeżeli jest zadeklarowane jako Object[]
:
private Object[] arr;
// to create it:
arr = new Object[3];
// to get an element:
E get(int i) { return (E)arr[i]; }
wadą tego jest to, że za każdym razem, gdy bierzesz coś z niego, musisz go rzucić pod numer E
, co oznacza, że zasadniczo używasz go jako pojemnika generycznego.
Jeżeli jest zadeklarowane jako E[]
:
private E[] arr;
// to create it:
arr = (E[])new Object[3];
// to get an element:
E get(int i) { return arr[i]; }
Zaletą jest to, że nie trzeba już rzucać kiedy się rzeczy z nim - zapewnia sprawdzania typu zastosowań arr
, jak generyczne pojemniki. Wadą jest to, że logicznie, obsada jest kłamstwem - wiemy, że stworzyliśmy obiekt, którego typem wykonawczym jest Object[]
, więc nie jest to instancja E[]
, chyba że E
jest Object
.
Jednak nie ma natychmiastowego problemu z robieniem tego, ponieważ E
jest usuwany do Object
wewnątrz metod instancji klasy.Jedynym sposobem, w jaki może wystąpić problem, jest to, że obiekt jest w jakiś sposób wystawiony na zewnątrz klasy (np. Zwrócony w metodzie, umieszczony w publicznym polu itp.) W wielkości, która wykorzystuje jego typ jako E[]
(której nie ma) :
// This would be bad. It would cause a class cast exception at the call site
E[] getArray() { return arr; }
Ale ArrayList
, a nawet każdy prawidłowo zaprojektowane klasa pojemnik, nigdy wystawiać szczegółów wdrażania, takie jak jego wewnętrznej tablicy na zewnątrz. Przełamałoby to między innymi abstrakcję. Tak długo, jak autor tej klasy zdaje sobie sprawę z tego, że nigdy nie wystawia tej tablicy, nie ma problemu z robieniem tego w ten sposób (z wyjątkiem może pomylić kolejną osobę, która widzi kod i jest tego nieświadomy) i jest wolna, aby wziąć zaletą zwiększonego sprawdzania typów, jakie przynosi ta metoda.
- 1. Dlaczego ArrayList korzysta z tymczasowej pamięci masowej?
- 2. ArrayList and String [] AND Object []
- 3. Dlaczego Unity korzysta z Lokalizatora Usług?
- 4. Java 8 Arraylist Implementacja hugeCapacity (int)
- 5. Dlaczego zapytanie NIE korzysta z mojego indeksu?
- 6. Dlaczego nikt nie korzysta z INotifyPropertyChanging?
- 7. Dlaczego DataMapper korzysta z mixinów a dziedziczenia?
- 8. Dlaczego typof (Object [,] []). Nazwa jest równa "Object [] [,]"?
- 9. Dlaczego usuwam element z niewłaściwej tablicy ArrayList?
- 10. Konwersja ArrayList wartość <Object> do byte []
- 11. Jak napisać ArrayList <Object> do pliku csv
- 12. Jak znaleźć duplikaty w ArrayList <Object>?
- 13. Jak przekonwertować ArrayList <Object> na ArrayList <String>?
- 14. Ktoś korzysta z SvnMapper?
- 15. Circular ArrayList (rozszerzenie ArrayList)
- 16. Dlaczego operator obsady nie korzysta z prywatnej bazy?
- 17. Dlaczego funkcja automatycznego wektoryzacji MSVC nie korzysta z AVX2?
- 18. Dlaczego mój program Matlaba korzysta z tak dużej ilości pamięci?
- 19. dlaczego mój widok w postgresql nie korzysta z indeksu?
- 20. Dlaczego moje zapytanie nie korzysta z indeksu w polu datetime?
- 21. Dlaczego system Windows 64 nadal korzysta z user32.dll itp.?
- 22. Dlaczego program SQL Server nie korzysta z mojego indeksu?
- 23. Calendar.before (Object when), why Object?
- 24. ArrayList zawiera inny ArrayList
- 25. Konwersja podmenu ArrayList ArrayList
- 26. Dlaczego ArrayList implementuje IList, ICollection, IEnumerable?
- 27. Dlaczego Arrays.asList() zwraca własną implementację ArrayList
- 28. ArrayList Unrolling
- 29. Z jakich portów korzysta XMPP?
- 30. Czy NSSearchField korzysta z NSTokenFieldCell?
Masz rację! Dziękuję Ci!!! – user485553
Można jeszcze zrobić niezaznaczoną obsadę: "E [] arr = (E []) nowy obiekt [3];" – Saintali
@Saintali: Możesz, ale dostaniesz 'ClassCastException' w momencie, w którym spróbujesz pracować z ta tablica. Spróbuj. – NPE