Programując w Androidzie, większość wartości tekstowych jest oczekiwana w CharSequence
.
Dlaczego? Jakie są korzyści i jakie są główne skutki CharSequence
nadmiernego używania String
?
Jakie są główne różnice i jakich problemów się spodziewamy, korzystając z nich i przechodząc od jednego do drugiego?
java
string
charsequence
e-satis
źródło
źródło
Odpowiedzi:
Ciągi to CharSequences , więc możesz po prostu używać Ciągów i nie martwić się. Android stara się tylko pomóc, pozwalając ci również określić inne obiekty CharSequence, takie jak StringBuffers.
źródło
CharSequence
javadoc: ten interfejs nie poprawia ogólnych umówequals
ihashCode
metod. Rezultat porównania dwóch obiektów, które implementują,CharSequence
jest zatem ogólnie nieokreślony . Każdy obiekt może być zaimplementowany przez inną klasę i nie ma gwarancji, że każda klasa będzie w stanie przetestować swoje instancje pod kątem równości z instancjami drugiej. Dlatego niewłaściwe jest używanie dowolnychCharSequence
instancji jako elementów zestawu lub kluczy na mapie.CharSequence
był modernizacją w JDK 1.4, aby wprowadzić wspólny interfejs o ograniczonym przeznaczeniu do obiektów zawierających sekwencje znaków. Niektóre z tych obiektów zawierają inny stan, więc zdefiniowanie goObject.equals
jako „zawiera tę samą sekwencję znaków” może nie mieć sensu .CharBuffer
Na przykład NIO odsłania znaki tylko między nimposition
alimit
nimCharSequence
, mimo że może zawierać wiele innych znaków.equals
/hashCode
włączonyObject
....Object
aniCharSequence
żaden interfejs nie jest wymagany, aby zapewnić równość rozsądku między implementacjami. Żadne dwa nieCollection
są wymagane do zapewnienia równościCollection
interfejsu, ale mogą to zrobić, jeśli chcą. IMHOCharSequence
powinno być ograniczone do danych wejściowych i wykorzystywane rzadziej w przypadku rodzajów zwrotów.CharSequence
= interfejsString
= konkretna implementacjaCharSequence
jest interfejsem .String
jest jedną z takich klas, konkretną implementacjąCharSequence
.Powiedziałeś:
Nie ma konwersji z
String
.String
obiekt jestCharSequence
.CharSequence
może wyprodukowaćString
. ZadzwońCharSequence::toString
. JeśliCharSequence
zdarza się, że aString
, to metoda zwraca odwołanie do własnego obiektu.Innymi słowy, każdy
String
jestCharSequence
, ale nie każdyCharSequence
jestString
.Programowanie do interfejsu
Zasadniczo programowanie w interfejsie jest lepsze niż programowanie w konkretnych klasach. Daje to elastyczność, dzięki czemu możemy przełączać się między konkretnymi implementacjami konkretnego interfejsu bez łamania innego kodu.
Tworząc interfejs API, który ma być używany przez różnych programistów w różnych sytuacjach, napisz swój kod, aby udostępnić i wziąć jak najbardziej ogólne interfejsy. Daje to programistom wywołującym swobodę korzystania z różnych implementacji tego interfejsu, w zależności od tego, która implementacja jest najlepsza dla danego kontekstu.
Na przykład spójrz na środowisko Java Collections Framework . Jeśli API daje lub bierze uporządkowanego zbioru obiektów, deklarują swoje metody, jak przy użyciu
List
zamiastArrayList
,LinkedList
albo jakakolwiek inna realizacja 3rd partiaList
.Pisząc szybką i brudną małą metodę, która ma być używana tylko przez Twój kod w jednym określonym miejscu, w przeciwieństwie do pisania interfejsu API do użycia w wielu miejscach, nie musisz zawracać sobie głowy bardziej ogólnym interfejsem niż konkretnym klasa. Ale nawet wtedy korzystanie z najbardziej ogólnego interfejsu, jaki możesz, może zaszkodzić.
String
wiesz, że masz jeden fragment tekstu, w całości w pamięci i jest niezmienna.CharSequence
nie wiesz, jakie mogą być szczególne cechy konkretnej implementacji.CharSequence
Przedmiot może stanowić ogromny fragment tekstu, a zatem ma wpływ na pamięć. Lub może być wiele fragmentów tekstu śledzonych osobno, które będą musiały zostać połączone podczas połączeniatoString
, a zatem występują problemy z wydajnością. Implementacja może nawet pobierać tekst ze zdalnej usługi, a zatem ma wpływ na opóźnienia.Zasadniczo nie będziesz nawracał się w tę iz powrotem. A
String
jest aCharSequence
. Jeśli twoja metoda deklaruje, że wymaga aCharSequence
, programista wywołujący może przekazaćString
obiekt lub przekazać coś innego, na przykład aStringBuffer
lubStringBuilder
. Kod twojej metody będzie po prostu używał tego, co zostało przekazane, wywołując dowolną zCharSequence
metod.Konwersja jest najbliższa, jeśli Twój kod otrzyma
CharSequence
i wiesz, że potrzebujeszString
. Być może łączysz się ze starym kodem zapisanym wString
klasie, a nie wCharSequence
interfejsie. A może Twój kod będzie intensywnie pracował z tekstem, na przykład powtarzając pętle lub analizując w inny sposób. W takim przypadku chcesz wykonać jeden możliwy hit wydajności tylko raz, więc zadzwoń ztoString
góry. Następnie kontynuuj pracę, używając tego, co wiesz, że jest pojedynczym fragmentem tekstu całkowicie w pamięci.Zakręcona historia
Zanotuj komentarze do zaakceptowanej odpowiedzi .
CharSequence
Interfejs został zamontować na istniejących struktur klasowych, więc istnieją pewne ważne subtelności (equals()
&hashCode()
). Zwróć uwagę na różne wersje Javy (1, 2, 4 i 5) oznaczone na klasach / interfejsach - z biegiem lat sporo rezygnacji. IdealnieCharSequence
byłoby na miejscu od samego początku, ale takie jest życie.Mój diagram klas poniżej może pomóc zobaczyć duży obraz typów ciągów w Javie 7/8. Nie jestem pewien, czy wszystkie są obecne w Androidzie, ale ogólny kontekst może nadal być dla Ciebie przydatny.
źródło
Uważam, że najlepiej jest używać CharSequence. Powodem jest to, że String implementuje CharSequence, dlatego możesz przekazać String do CharSequence, JEDNAK nie możesz przekazać CharSequence do String, ponieważ CharSequence nie implementuje String. TAKŻE, w Androidzie
EditText.getText()
metoda zwraca wartość Edytowalną, która również implementuje CharSequence i może być łatwo przekazana do jednego, a nie łatwo do Łańcucha. CharSequence obsługuje wszystko!źródło
charSequence.toString()
Zasadniczo użycie interfejsu pozwala na różnicowanie implementacji przy minimalnym uszkodzeniu dodatkowym. Mimo że java.lang.String są bardzo popularne, może się zdarzyć, że w pewnych kontekstach ktoś może chcieć użyć innej implementacji. Budując interfejs API wokół CharSequences zamiast Strings, kod daje taką możliwość.
źródło
Jest to prawie na pewno powód wydajności. Na przykład, wyobraź sobie parser, który przechodzi przez 500k ByteBuffer zawierający łańcuchy.
Istnieją 3 podejścia do zwracania treści ciągu:
Zbuduj String [] w czasie analizy, po jednym znaku na raz. Zajmie to zauważalnie dużo czasu. Możemy użyć == zamiast .equals do porównania referencji w pamięci podręcznej.
Zbuduj int [] z przesunięciami w czasie analizy, a następnie dynamicznie buduj String, gdy nastąpi get (). Każdy ciąg będzie nowym obiektem, więc żadne buforowanie nie zwróci wartości i użycie ==
Zbuduj CharSequence [] w czasie analizy. Ponieważ żadne nowe dane nie są przechowywane (poza przesunięciami do bufora bajtów), parsowanie jest znacznie niższe niż # 1. W czasie nie musimy budować Ciągu, więc uzyskana wydajność jest równa # 1 (znacznie lepsza niż # 2), ponieważ zwracamy tylko odwołanie do istniejącego obiektu.
Oprócz korzyści przetwarzania uzyskanych za pomocą CharSequence, zmniejszasz także zużycie pamięci, nie powielając danych. Na przykład, jeśli masz bufor zawierający 3 akapity tekstu i chcesz zwrócić wszystkie 3 lub pojedynczy akapit, potrzebujesz 4 ciągów znaków, które to reprezentują. Używając CharSequence potrzebujesz tylko 1 bufora z danymi i 4 instancji implementacji CharSequence, która śledzi początek i długość.
źródło
CharSequence
implementację.CharSequence
jest interfejsem - z definicji nie ma żadnych szczegółów implementacji, które omawiasz, ponieważ nie ma własnej implementacji . AString
jest jedną z kilku konkretnych klas, które implementująCharSequence
interfejs. WięcString
jestCharSequence
. Możesz porównać szczegóły dotyczące wydajnościString
vsStringBuffer
vsStringBuilder
, ale nieCharSequence
. Pisanie „korzyści z przetwarzania uzyskiwanych za pomocą CharSequence” nie ma znaczenia.Problem, który pojawia się w praktycznym kodzie Androida, polega na tym, że porównywanie ich z CharSequence.equals jest prawidłowe, ale niekoniecznie działa zgodnie z przeznaczeniem.
Porównanie powinno zostać wykonane przez
źródło
CharSequence
A
CharSequence
jest interfejsem, a nie rzeczywistą klasą. Interfejs to tylko zbiór reguł (metod), które klasa musi zawierać, jeśli implementuje interfejs. W Androidzie aCharSequence
jest parasolem na różnego rodzaju ciągi tekstowe. Oto niektóre z typowych:String
(niezmienny tekst bez rozpiętości stylów)StringBuilder
(tekst zmienny bez stylizacji)SpannableString
(niezmienny tekst z rozpiętością stylów)SpannableStringBuilder
(tekst zmienny z rozpiętością stylów)(Możesz przeczytać więcej o różnicach między nimi tutaj .)
Jeśli masz
CharSequence
obiekt, to w rzeczywistości jest to obiekt jednej z implementujących klasCharSequence
. Na przykład:Zaletą posiadania ogólnego typu parasola
CharSequence
jest to, że można obsługiwać wiele typów za pomocą jednej metody. Na przykład, jeśli mam metodę, która przyjmujeCharSequence
jako parametr, mogłabym przekazać aString
lub aSpannableStringBuilder
i obsłużyłaby jedną z nich.Strunowy
Można powiedzieć, że a
String
jest tylko jednym rodzajemCharSequence
. Jednak w przeciwieństwie doCharSequence
, jest to klasa rzeczywista, więc możesz tworzyć z niej obiekty. Więc możesz to zrobić:ale nie możesz tego zrobić:
Ponieważ
CharSequence
jest to tylko lista reguł, które sąString
zgodne, możesz to zrobić:Oznacza to, że za każdym razem sposób prosi o
CharSequence
, to jest w porządku, aby nadać muString
.Jednak przeciwieństwo nie jest prawdą. Jeśli metoda przyjmuje
String
parametr, nie można przekazać mu czegoś, co jest ogólnie znane jako aCharSequence
, ponieważ może to być faktycznieSpannableString
inny rodzajCharSequence
.źródło
CharSequence
jest interfejsem iString
implementuje go. Możesz utworzyć instancję,String
ale nie możesz tego zrobić,CharSequence
ponieważ jest to interfejs. Inne implementacje można znaleźćCharSequence
na oficjalnej stronie Java.źródło
CharSequence to czytelna sekwencja wartości char, która implementuje String. ma 4 metody
Proszę zapoznać się z dokumentacją Dokumentacja CharSequence
źródło
CharSequence
nie implementujeString
. Ale odwrotność jest prawdziwa.