VS String CharSequence di Jawa?

421

Pemrograman dalam Android, sebagian besar nilai teks diharapkan masuk CharSequence.

Mengapa demikian? Apa manfaatnya, dan apa dampak utama dari penggunaan CharSequenceberlebihan String?

Apa perbedaan utama, dan masalah apa yang diharapkan, saat menggunakannya, dan mengubah satu sama lain?

e-satis
sumber
1
Jawaban yang lebih baik dapat ditemukan di Perbedaan tepat antara CharSequence dan String di java
Suragch

Jawaban:

343

String adalah CharSequences , jadi Anda bisa menggunakan String dan tidak khawatir. Android hanya berusaha membantu dengan memungkinkan Anda juga menentukan objek CharSequence lainnya, seperti StringBuffers.

Zarkonnen
sumber
94
Kecuali ketika Android memberi saya CharSequence dalam panggilan balik dan saya membutuhkan String - panggil charSeq.toString ().
Martin Konicek
100
Tapi ingatlah peringatan ini dari CharSequencejavadoc: Antarmuka ini tidak memperbaiki kontrak umum equalsdan hashCodemetode. CharSequenceOleh karena itu, hasil membandingkan dua objek yang mengimplementasikan secara umum tidak terdefinisi . Setiap objek dapat diimplementasikan oleh kelas yang berbeda, dan tidak ada jaminan bahwa masing-masing kelas akan dapat menguji instansnya untuk persamaan dengan yang lainnya. Oleh karena itu tidak tepat untuk menggunakan CharSequenceinstance sembarang sebagai elemen dalam set atau sebagai kunci dalam peta.
Trevor Robinson
3
@Pacerier: Saya pikir ini lebih merupakan batasan praktis. CharSequenceadalah retrofit di JDK 1.4 untuk memperkenalkan antarmuka umum tujuan terbatas ke objek yang berisi urutan karakter. Beberapa objek tersebut berisi keadaan lain, jadi mungkin tidak masuk akal untuk mendefinisikan Object.equalssebagai "berisi urutan karakter yang sama". NIO CharBuffer, misalnya, hanya mengekspos karakter antara positiondan limitsebagai CharSequence, meskipun berpotensi menahan banyak karakter lain.
Trevor Robinson
6
@ TrevorRobinson, Jadi bug desain mengalami equals/ hashCodeaktif Objectdi tempat pertama ....
Pacerier
4
@Pacerier: IMHO Tidak ada bug desain di salah satu Objectatau CharSequence, tidak ada antarmuka yang diperlukan untuk memberikan kewarasan kesetaraan antara implementasi. Tidak ada dua Collections yang diperlukan untuk memberikan persamaan antar Collectionantarmuka, tetapi mereka bisa jika mereka mau. IMHO CharSequenceharus dibatasi pada input dan digunakan lebih sedikit untuk jenis pengembalian.
Brett Ryan
58

CharSequence= antarmuka
String= implementasi konkret

Kamu berkata:

mengkonversi dari satu ke yang lain

Tidak ada konversi dari String.

  • Setiap Stringobjek adalah a CharSequence.
  • Setiap CharSequencedapat menghasilkan a String. Panggil CharSequence::toString. Jika CharSequencekebetulan menjadi String, maka metode mengembalikan referensi ke objeknya sendiri.

Dengan kata lain, setiap Stringadalah a CharSequence, tetapi tidak setiap CharSequenceadalah a String.

Pemrograman ke antarmuka

Pemrograman dalam Android, sebagian besar nilai teks diharapkan di CharSequence.

Mengapa demikian? Apa manfaatnya, dan apa dampak utama menggunakan CharSequence over String?

Secara umum, pemrograman ke antarmuka lebih baik daripada pemrograman ke kelas konkret. Ini menghasilkan fleksibilitas, sehingga kami dapat beralih di antara implementasi konkret antarmuka tertentu tanpa melanggar kode lainnya.

Saat mengembangkan API untuk digunakan oleh berbagai programer dalam berbagai situasi, tulis kode Anda untuk memberi dan mengambil antarmuka yang paling umum. Ini memberi programmer panggilan kebebasan untuk menggunakan berbagai implementasi dari antarmuka itu, implementasi mana yang terbaik untuk konteks khusus mereka.

Misalnya, lihat Java Collections Framework . Jika API Anda memberi atau mengambil koleksi memerintahkan objek, menyatakan metode Anda sebagai menggunakan Listbukan ArrayList, LinkedList, atau implementasi pihak ke-3 lainnya List.

Saat menulis metode kecil cepat-dan-kotor untuk hanya digunakan oleh kode Anda di satu tempat tertentu, bukan menulis API yang akan digunakan di banyak tempat, Anda tidak perlu repot-repot menggunakan antarmuka yang lebih umum daripada beton khusus kelas. Tetapi meskipun begitu, tidak ada salahnya menggunakan antarmuka paling umum yang Anda bisa.

Apa perbedaan utama, dan masalah apa yang diharapkan, saat menggunakannya,

  • Dengan StringAnda tahu Anda memiliki satu bagian teks, seluruhnya dalam memori, dan tidak berubah.
  • Dengan CharSequence, Anda tidak tahu apa fitur khusus dari implementasi konkret mungkin.

The CharSequenceobjek mungkin mewakili potongan besar teks, dan karena itu memiliki implikasi memori. Atau mungkin banyak potongan teks yang dilacak secara terpisah yang perlu dijahit bersama saat Anda menelepon toString, dan karenanya memiliki masalah kinerja. Implementasinya bahkan dapat mengambil teks dari layanan jarak jauh, dan karenanya memiliki implikasi latensi.

dan mengkonversi dari satu ke yang lain?

Anda biasanya tidak akan mengkonversi bolak-balik. A String adalah a CharSequence. Jika metode Anda menyatakan bahwa dibutuhkan CharSequence, pemrogram pemanggil dapat melewatkan Stringobjek, atau mungkin melewatkan sesuatu yang lain seperti a StringBufferatau StringBuilder. Kode metode Anda hanya akan menggunakan apa pun yang diteruskan, memanggil salah satu CharSequencemetode.

Yang paling dekat dengan konversi Anda adalah jika kode Anda menerima CharSequencedan Anda tahu Anda perlu String. Mungkin Anda berinteraksi dengan kode lama yang ditulis ke Stringkelas daripada ditulis ke CharSequenceantarmuka. Atau mungkin kode Anda akan bekerja secara intensif dengan teks, seperti mengulang berulang kali atau menganalisis. Dalam hal ini, Anda hanya ingin mengambil satu kemungkinan performa yang dicapai hanya sekali, jadi Anda menelepon terlebih dahulu toString. Kemudian lanjutkan dengan pekerjaan Anda menggunakan apa yang Anda tahu sebagai satu bagian teks yang seluruhnya ada dalam memori.

Sejarah bengkok

Perhatikan komentar yang dibuat pada Jawaban yang diterima . The CharSequenceantarmuka itu dipasang ke struktur kelas yang ada, jadi ada beberapa kehalusan penting ( equals()& hashCode()). Perhatikan berbagai versi Java (1, 2, 4 & 5) yang ditandai pada kelas / antarmuka — cukup banyak churn selama bertahun-tahun. Idealnya CharSequencesudah ada sejak awal, tetapi itulah kehidupan.

Diagram kelas saya di bawah ini dapat membantu Anda melihat gambaran besar tipe string di Java 7/8. Saya tidak yakin apakah semua ini ada di Android, tetapi konteks keseluruhan masih terbukti bermanfaat bagi Anda.

diagram berbagai kelas dan antarmuka yang terkait dengan string

Basil Bourque
sumber
2
Apakah Anda membuat diagram ini sendiri? bertanya-tanya apakah ada katalog diagram ini untuk struktur data yang berbeda.
user171943
4
@ user171943 Diciptakan oleh saya, kerajinan tangan menggunakan aplikasi OmniGraffle dari OmniGroup.
Basil Bourque
37

Saya percaya yang terbaik adalah menggunakan CharSequence. Alasannya adalah bahwa String mengimplementasikan CharSequence, oleh karena itu Anda dapat meneruskan sebuah String ke dalam CharSequence, NAMUN Anda tidak dapat meneruskan sebuah CharSequence ke dalam sebuah String, karena CharSequence tidak mengimplementasikan String. JUGA, di Android EditText.getText()metode mengembalikan Editable, yang juga mengimplementasikan CharSequence dan dapat dilewatkan dengan mudah menjadi satu, sementara tidak mudah menjadi String. CharSequence menangani semuanya!

Palsu
sumber
7
Anda dapat melakukannyacharSequence.toString()
Jorge Fuentes González
1
@ jorge: Kecuali itu akan relatif tidak efisien jika urutannya bisa berubah (atau karena alasan apa pun memerlukan salinan karakter untuk membuat string yang tidak dapat diubah).
Lawrence Dol
penjelasan yang sangat bagus ..!
majurageerthan
23

Secara umum menggunakan antarmuka memungkinkan Anda untuk memvariasikan implementasi dengan kerusakan jaminan minimal. Meskipun java.lang.String sangat populer mungkin dalam konteks tertentu seseorang mungkin ingin menggunakan implementasi lain. Dengan membangun API di sekitar CharSequences daripada Strings, kode memberi seseorang peluang untuk melakukan itu.

Itay Maman
sumber
8

Ini hampir pasti alasan kinerja. Misalnya, bayangkan parser yang melewati string 500k ByteBuffer yang berisi.

Ada 3 pendekatan untuk mengembalikan konten string:

  1. Bangun String [] pada waktu parse, satu karakter pada satu waktu. Ini akan memakan banyak waktu. Kita bisa menggunakan == daripada .equals untuk membandingkan referensi yang di-cache.

  2. Bangun int [] dengan offset pada waktu parse, lalu bangun String secara dinamis saat get () terjadi. Setiap String akan menjadi objek baru, jadi tidak ada caching yang mengembalikan nilai dan menggunakan ==

  3. Bangun CharSequence [] pada saat parse. Karena tidak ada data baru disimpan (selain offset ke buffer byte), penguraian jauh lebih rendah daripada # 1. Saat mendapatkan, kita tidak perlu membuat String, jadi mendapatkan kinerja sama dengan # 1 (jauh lebih baik dari # 2), karena kami hanya mengembalikan referensi ke objek yang ada.

Selain keuntungan pemrosesan yang Anda dapatkan menggunakan CharSequence, Anda juga mengurangi jejak memori dengan tidak menggandakan data. Misalnya, jika Anda memiliki buffer yang berisi 3 paragraf teks, dan ingin mengembalikan semua 3 atau satu paragraf, Anda perlu 4 Strings untuk mewakili ini. Menggunakan CharSequence Anda hanya perlu 1 buffer dengan data, dan 4 contoh implementasi CharSequence yang melacak awal dan panjang.

Phil Lello
sumber
6
referensi tlg. Kedengarannya seperti menebak secara acak apa yang terjadi. juga saya tidak menemukan argumen Anda valid. satu mungkin hanya menyimpan bytebuffer 500k sebagai string di tempat pertama dan hanya mengembalikan substring, yang gila cepat, dan jauh lebih umum.
kritzikratzi
6
@kritzikratzi - pada JDK7, substring pada String tidak lagi berbagi array yang mendasarinya, dan bukan "gila cepat". Dibutuhkan O (N) waktu dalam panjang substring, dan menghasilkan salinan karakter yang mendasari setiap kali Anda menyebutnya (jadi banyak sampah).
BeeOnRope
@ kritzikratzi Saya percaya alasan untuk perubahan adalah bahwa, jika salinan itu tidak dibuat, String asli akan dipertahankan untuk seumur hidup semua substring. Mengingat bahwa substring biasanya hanya sebagian kecil dari dokumen asli dan dapat bertahan tanpa batas waktu tergantung pada bagaimana mereka digunakan, ini seringkali akan menghasilkan lebih banyak sampah jika substring digunakan lebih lama daripada string aslinya. Alt yang menarik mungkin untuk menentukan apakah akan menyalin atau tidak berdasarkan rasio substring ke ukuran string induk, tetapi Anda harus menggulung CharSequenceimplementasi Anda sendiri untuk itu.
JAB
1
Mungkin saya telah melewatkan intinya, tetapi jawaban ini tidak masuk akal. A CharSequenceadalah antarmuka - menurut definisi, ia tidak memiliki detail implementasi yang Anda diskusikan karena ia tidak memiliki implementasi sendiri. A Stringadalah salah satu dari beberapa kelas konkret yang mengimplementasikan CharSequenceantarmuka. Jadi a String adalah a CharSequence. Anda dapat membandingkan detail kinerja Stringvs StringBuffervs StringBuilder, tetapi tidak CharSequence. Menulis "memproses keuntungan yang Anda dapatkan menggunakan CharSequence" tidak ada artinya.
Basil Bourque
7

Masalah yang muncul dalam kode Android praktis adalah membandingkannya dengan CharSequence.equals valid tetapi tidak selalu berfungsi sebagaimana dimaksud.

EditText t = (EditText )getView(R.id.myEditText); // Contains "OK"
Boolean isFalse = t.getText().equals("OK"); // will always return false.

Perbandingan harus dilakukan oleh

("OK").contentEquals(t.GetText()); 
Crypth
sumber
5

Konsekuensi

A CharSequenceadalah antarmuka, bukan kelas yang sebenarnya. Antarmuka hanyalah seperangkat aturan (metode) yang harus dimiliki kelas jika mengimplementasikan antarmuka. Di Android a CharSequenceadalah payung untuk berbagai jenis string teks. Berikut adalah beberapa yang umum:

(Anda dapat membaca lebih lanjut tentang perbedaan antara ini di sini .)

Jika Anda memiliki CharSequenceobjek, maka sebenarnya objek dari salah satu kelas yang diimplementasikan CharSequence. Sebagai contoh:

CharSequence myString = "hello";
CharSequence mySpannableStringBuilder = new SpannableStringBuilder();

Manfaat memiliki jenis payung umum seperti CharSequenceadalah Anda dapat menangani banyak jenis dengan satu metode. Sebagai contoh, jika saya memiliki metode yang menggunakan CharSequenceparameter, saya bisa memasukkan a Stringatau a SpannableStringBuilderdan itu akan menangani salah satunya.

public int getLength(CharSequence text) {
    return text.length();
}

Tali

Anda dapat mengatakan bahwa Stringhanya satu jenis CharSequence. Namun, tidak seperti CharSequence, ini adalah kelas yang sebenarnya, sehingga Anda dapat membuat objek dari itu. Jadi Anda bisa melakukan ini:

String myString = new String();

tetapi Anda tidak bisa melakukan ini:

CharSequence myCharSequence = new CharSequence(); // error: 'CharSequence is abstract; cannot be instantiated

Karena CharSequencehanya daftar aturan yang Stringsesuai, Anda dapat melakukan ini:

CharSequence myString = new String();

Itu berarti bahwa setiap kali suatu metode meminta CharSequence, tidak masalah untuk memberikannya String.

String myString = "hello";
getLength(myString); // OK

// ...

public int getLength(CharSequence text) {
    return text.length();
}

Namun, yang terjadi adalah sebaliknya. Jika metode ini mengambil Stringparameter, Anda tidak bisa meneruskannya sesuatu yang hanya dikenal sebagai a CharSequence, karena mungkin sebenarnya berupa SpannableStringatau sejenisnya CharSequence.

CharSequence myString = "hello";
getLength(myString); // error

// ...

public int getLength(String text) {
    return text.length();
}
Suragch
sumber
0

CharSequenceadalah antarmuka dan Stringmengimplementasikannya. Anda dapat membuat instantiate Stringtetapi Anda tidak bisa melakukannya CharSequencekarena itu adalah antarmuka. Anda dapat menemukan implementasi lain di CharSequencedalam situs web resmi Java.

Xiaogang
sumber
-4

CharSequence adalah urutan nilai char yang dapat dibaca yang mengimplementasikan String. ini memiliki 4 metode

  1. karakter (indeks int)
  2. panjangnya()
  3. subSequence (int start, int end)
  4. toString ()

Silakan lihat dokumentasi dokumentasi CharSequence

Srinivas Thammanaboina
sumber
6
CharSequencetidak menerapkan String. Kebalikannya benar.
seh
1
Harap hapus jawaban yang tidak masuk akal ini
J. Doe