Szukam metody w Javie, która zwróci segment tablicy. Przykładem może być tablica bajtów zawierająca 4. i 5. bajt tablicy bajtów. Nie chcę tworzyć nowej tablicy bajtów w pamięci sterty, aby to zrobić. W tej chwili mam następujący kod:
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
Chciałbym wiedzieć, czy istnieje sposób, aby po prostu zrobić, doSomething(bigArray.getSubArray(4, 2))
gdzie 4 to przesunięcie, a 2 to na przykład długość.
Odpowiedzi:
Zastrzeżenie: Ta odpowiedź nie jest zgodna z ograniczeniami pytania:
( Szczerze mówiąc, uważam, że moja odpowiedź zasługuje na usunięcie. Odpowiedź @ Unique72 jest poprawna. Imma pozwól, aby ta edycja trochę usiadła, a następnie usunę tę odpowiedź. )
Nie wiem, jak to zrobić bezpośrednio z tablicami bez dodatkowego przydziału sterty, ale inne odpowiedzi korzystające z otoki podlisty mają dodatkowy przydział tylko dla otoki - ale nie dla tablicy - co byłoby przydatne w przypadku duża tablica.
To powiedziawszy, jeśli ktoś szuka zwięzłości, metoda użytkowa
Arrays.copyOfRange()
została wprowadzona w Javie 6 (pod koniec 2006 roku?):źródło
copyOfRange
. Gdyby było to źródło zamknięte, może by przeszło. :)Arrays.asList(myArray)
deleguje do newArrayList(myArray)
, który nie kopiuje tablicy, a jedynie przechowuje referencję. UżywanieList.subList(start, end)
później powoduje, że poSubList
prostu odwołuje się do oryginalnej listy (która wciąż tylko odwołuje się do tablicy). Brak kopiowania tablicy lub jej zawartości, po prostu tworzenie opakowania, a wszystkie zaangażowane listy są wspierane przez oryginalną tablicę. (Myślałem, że będzie cięższy.)źródło
Arrays
myląco nazywanejArrayList
, ale która tak naprawdę jestList
wokół tablicy, w przeciwieństwie dojava.util.ArrayList
której tworzy kopię. Brak nowych przydziałów (zawartości listy) i brak zależności stron trzecich. To, moim zdaniem, najbardziej poprawna odpowiedź.byte[]
w jego przypadku). Wszystko, co dostaniesz, toList<byte[]>
. A zmianabyte[] bigArray
naByte[] bigArray
może spowodować znaczne obciążenie pamięci.sun.misc.Unsafe
klasa.Jeśli szukasz sposobu aliasingu w stylu wskaźnika, abyś nawet nie musiał przydzielać miejsca i kopiować danych, to uważam, że nie masz szczęścia.
System.arraycopy()
skopiuje ze źródła do miejsca docelowego, a wydajność tego narzędzia jest deklarowana. Musisz przydzielić tablicę docelową.źródło
array*copy*()
ponownie używać tej samej pamięci? Czy to nie jest dokładnie odwrotne, niż oczekiwałby dzwoniący?Jednym ze sposobów jest zawinięcie tablicy
java.nio.ByteBuffer
, użycie absolutnych funkcji put / get i podzielenie bufora na pracę na podtablicy.Na przykład:
Należy pamiętać, że trzeba zadzwonić zarówno
wrap()
islice()
, ponieważwrap()
sama ma wpływ jedynie względną put / uzyskać funkcje, nie tych bezwzględnych.ByteBuffer
może być nieco trudny do zrozumienia, ale najprawdopodobniej jest skutecznie wdrożony i warto się go nauczyć.źródło
StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer, 0, readBytes))
Arrays.copyOfRange
?Arrays.copyOfRange
jest prawdopodobnie bardziej wydajna. Ogólnie rzecz biorąc, musisz zmierzyć dla konkretnego przypadku użycia.Użyj java.nio.Buffer. Jest to lekkie opakowanie do buforów różnych pierwotnych typów i pomaga zarządzać krojeniem, pozycją, konwersją, kolejnością bajtów itp.
Jeśli bajty pochodzą ze strumienia, bufory NIO mogą używać „trybu bezpośredniego”, który tworzy bufor wspierany przez zasoby rodzime. Może to poprawić wydajność w wielu przypadkach.
źródło
Możesz użyć ArrayUtils.subarray w apache commons. Nie jest idealny, ale jest nieco bardziej intuicyjny niż
System.arraycopy.
Minusem jest to, że wprowadza on kolejną zależność do kodu.źródło
Widzę, że odpowiedź na podlistę jest już tutaj, ale oto kod, który pokazuje, że jest to prawdziwa lista podrzędna, a nie kopia:
Nie sądzę jednak, że istnieje dobry sposób, aby zrobić to bezpośrednio z tablicami.
źródło
źródło
Jedną z opcji byłoby przekazanie całej tablicy oraz indeksów początkowej i końcowej oraz iteracja między nimi zamiast iteracji po całej przekazanej tablicy.
źródło
Do
List
s pozwalają na wykorzystanie i pracę zsubList
czegoś przejrzysty. Prymitywne tablice wymagałyby śledzenia pewnego limitu przesunięcia.ByteBuffer
s mają podobne opcje, jak słyszałem.Edycja: jeśli jesteś odpowiedzialny za przydatną metodę, możesz po prostu zdefiniować ją za pomocą granic (tak jak w wielu metodach związanych z tablicą w samej Javie:
Nie jest jednak jasne, czy pracujesz nad elementami tablicy, np. Obliczasz coś i zapisujesz wynik?
źródło
Odwołania Java zawsze wskazują na obiekt. Obiekt ma nagłówek, który między innymi identyfikuje konkretny typ (więc rzutowanie może się nie powieść
ClassCastException
). W przypadku tablic początek obiektu obejmuje również długość, następnie dane są zapisywane bezpośrednio w pamięci (technicznie implementacja może robić, co chce, ale głupio byłoby robić cokolwiek innego). Więc możesz; t mieć odwołanie, które wskazuje gdzieś w tablicy.Wskaźniki w C wskazują gdziekolwiek i na cokolwiek, a możesz wskazać środek tablicy. Ale nie możesz bezpiecznie rzucić ani dowiedzieć się, jak długa jest tablica. W D wskaźnik zawiera przesunięcie w bloku pamięci i długości (lub równoważnie wskaźnik do końca, nie pamiętam, co faktycznie robi implementacja). Pozwala to D na dzielenie tablic. W C ++ miałbyś dwa iteratory wskazujące początek i koniec, ale C ++ jest trochę dziwne.
Wracając do Javy, nie, nie możesz. Jak wspomniano, NIO
ByteBuffer
pozwala owinąć tablicę, a następnie pokroić ją, ale daje niezręczny interfejs. Możesz oczywiście kopiować, co jest prawdopodobnie znacznie szybsze niż mogłoby się wydawać. Możesz wprowadzić swoją własnąString
abstrakcję, która pozwala pokroić tablicę (obecna implementacja SunString
machar[]
odniesienie oraz przesunięcie początkowe i długość, implementacja o wyższej wydajności ma po prostuchar[]
).byte[]
jest niski poziom, ale każda abstrakcja oparta na klasach spowoduje okropny bałagan w składni, aż do JDK7 (być może).źródło
substring
w HotSpot (zapomnij, która kompilacja to zmieniła). Dlaczego mówisz, że JDK7 pozwala na lepszą składnię niż ByteBuffer?[]
notację tablicową na typach zdefiniowanych przez użytkownika, takich jakList
iByteBuffer
. Wciąż czekam ...@ unikalna72 odpowiedź jako prosta funkcja lub linia, może być konieczne zastąpienie obiektu odpowiednim typem klasy, który chcesz „pokroić”. Dostępne są dwa warianty odpowiadające różnym potrzebom.
źródło
Co powiesz na cienkie
List
opakowanie?(Nieprzetestowane)
źródło
Byte
obiekty dla wszystkichbyte
wartości są buforowane. Więc boks nad głową powinien być raczej powolny.Musiałem iterować przez koniec tablicy i nie chciałem jej kopiować. Moje podejście polegało na stworzeniu iterowalnego ciągu tablicy.
źródło
Jest to nieco lżejsze niż Arrays.copyOfRange - brak zasięgu lub wartość ujemna
źródło