Struktury danych .NET:
Więcej informacji na temat tego, dlaczego ArrayList i List są tak naprawdę różne
Tablice
Jak twierdzi jeden użytkownik, tablice są kolekcją „starej szkoły” (tak, tablice są uważane za kolekcję, ale nie są częścią System.Collections
). Ale czym jest „stara szkoła” o tablicach w porównaniu z innymi kolekcjami, tj. Tymi, które wymieniłeś w swoim tytule (tutaj ArrayList i List (Of T))? Zacznijmy od podstaw, patrząc na tablice.
Na początek tablice w Microsoft .NET to „mechanizmy, które pozwalają traktować kilka [związanych logicznie] elementów jako jedną kolekcję” (patrz link do artykułu). Co to znaczy? Tablice przechowują poszczególne elementy (elementy) sekwencyjnie, jeden po drugim w pamięci z adresem początkowym. Korzystając z tablicy, możemy łatwo uzyskać dostęp do sekwencyjnie przechowywanych elementów zaczynających się pod tym adresem.
Poza tym i w przeciwieństwie do programowania 101 powszechnych koncepcji, tablice mogą być bardzo złożone:
Tablice mogą być jednowymiarowe, wielowymiarowe lub zniszczone (o tablicach postrzępionych warto przeczytać). Same tablice nie są dynamiczne: po zainicjowaniu tablica o rozmiarze n rezerwuje wystarczająco dużo miejsca do przechowywania n liczby obiektów. Liczba elementów w tablicy nie może rosnąć ani kurczyć się. Dim _array As Int32() = New Int32(100)
rezerwuje wystarczającą ilość miejsca w bloku pamięci, aby tablica zawierała 100 obiektów typu pierwotnego Int32 (w tym przypadku tablica jest inicjowana tak, aby zawierała 0). Adres tego bloku jest zwracany do _array
.
Zgodnie z artykułem specyfikacja języka wspólnego (CLS) wymaga, aby wszystkie tablice były zerowane. Tablice w .NET obsługują tablice niezerowe; jest to jednak mniej powszechne. W wyniku „powszechności” tablic zerowych Microsoft poświęcił wiele czasu na optymalizację ich wydajności ; dlatego macierze jednowymiarowe oparte na zerach (SZ) są „specjalne” - i naprawdę najlepsza implementacja tablicy (w przeciwieństwie do wielowymiarowych itp.) - ponieważ SZ mają specyficzne instrukcje języka pośredniego do manipulowania nimi.
Tablice są zawsze przekazywane przez odniesienie (jako adres pamięci) - ważny element układanki Array, którą należy znać. Podczas gdy sprawdzają granice (wyrzucą błąd), sprawdzanie granic można również wyłączyć w tablicach.
Ponownie, największą przeszkodą dla tablic jest to, że nie można ich zmieniać rozmiarów. Mają „stałą” pojemność. Przedstawiamy ArrayList i List (Of T) w naszej historii:
ArrayList - lista ogólna
ArrayList (wraz z List(Of T)
- chociaż istnieją pewne krytyczne różnice tutaj wyjaśnione później) - to chyba najlepiej traktowane jako kolejnego dodatku do kolekcji (w szerokim tego słowa znaczeniu). ArrayList dziedziczy po interfejsie IList (potomek „ICollection”) interfejsu. Same ArrayLists są bardziej obszerne - wymagają większego obciążenia - niż Listy.
IList
umożliwia implementacji traktowanie ArrayLists jako list o stałej wielkości (takich jak tablice); jednak oprócz dodatkowej funkcjonalności dodanej przez ArrayLists, nie ma rzeczywistych korzyści z używania ArrayLists, które mają stały rozmiar, ponieważ ArrayLists (ponad tablicami) w tym przypadku są znacznie wolniejsze.
Z mojego czytania, ArrayLists nie można postrzępić: „Używanie tablic wielowymiarowych jako elementów ... nie jest obsługiwane”. Znów kolejny gwóźdź do trumny ArrayLists. ArrayLists również nie są „wpisane” - co oznacza, że pod spodem wszystko, ArrayList jest po prostu Array dynamiczne obiektów: Object[]
. Wymaga to dużej ilości boksu (niejawnego) i rozpakowania (jawnego) podczas implementacji ArrayLists, ponownie zwiększając ich obciążenie.
Nieuzasadniona myśl: myślę, że pamiętam albo czytając lub słysząc od jednego z moich profesorów, że ArrayLists są rodzajem drania koncepcyjnego, który próbuje przenieść się z Tablic do Kolekcji typu List, tj. Chociaż kiedyś był wielkim ulepszeniem Tablic, nie są już najlepszą opcją, ponieważ dokonano dalszego rozwoju kolekcji
List (Of T): What ArrayList stał się (i miał nadzieję, że będzie)
Różnica w użyciu pamięci jest na tyle znacząca, że List (Of Int32) zużył 56% mniej pamięci niż ArrayList zawierający ten sam prymitywny typ (8 MB vs. 19 MB w powyższej demonstracji połączonej z dżentelmenem: ponownie, połączony tutaj ) - chociaż jest to wynik złożony z komputera 64-bitowego. Ta różnica naprawdę pokazuje dwie rzeczy: po pierwsze (1), „obiekt” typu Int32 w ramce (ArrayList) jest znacznie większy niż czysty typ pierwotny Int32 (List); po drugie (2) różnica jest wykładnicza w wyniku wewnętrznego działania 64-bitowej maszyny.
Jaka jest różnica i czym jest lista (Of T) ? MSDN definiuje List(Of T)
jako „… silnie wpisaną listę obiektów, do których można uzyskać dostęp za pomocą indeksu”. Znaczenie ma tutaj bit „silnie typowany”: Lista (Of T) „rozpoznaje” typy i przechowuje obiekty jako ich typy. Tak więc an Int32
jest przechowywane jako Int32
a nie Object
typ. Eliminuje to problemy spowodowane przez boksowanie i rozpakowywanie.
MSDN określa, że ta różnica ma zastosowanie tylko podczas przechowywania typów pierwotnych, a nie typów referencyjnych. Zbyt duża różnica występuje naprawdę na dużą skalę: ponad 500 elementów. Co bardziej interesujące, w dokumentacji MSDN czytamy: „Korzystną dla Ciebie implementacją jest zastosowanie implementacji klasy List (Of T) zamiast klasy ArrayList ....”
Zasadniczo List (Of T) jest ArrayList, ale lepiej. Jest to „ogólny odpowiednik” ArrayList. Podobnie jak ArrayList, nie ma gwarancji, że zostanie posortowane do czasu posortowania (przejdź do rysunku). Lista (Of T) ma również kilka dodatkowych funkcji.