CharSequence VS String in Java?


421

Programmando in Android, è prevista la maggior parte dei valori di testo in CharSequence.

Perché? Qual è il vantaggio, e quali sono i principali impatti dell'utilizzo di CharSequencesopra String?

Quali sono le principali differenze e quali sono i problemi che ci si attende, durante l'utilizzo e la conversione da uno all'altro?


1
Risposte migliori si possono trovare alla differenza esatta tra CharSequence e String in Java
Suragch,

Risposte:


343

Le stringhe sono CharSequences , quindi puoi semplicemente usare le stringhe e non preoccuparti. Android sta semplicemente cercando di essere utile consentendo di specificare anche altri oggetti CharSequence, come StringBuffers.


94
Tranne quando Android mi passa una CharSequence in una richiamata e ho bisogno di una stringa, chiama charSeq.toString ().
Martin Konicek,

100
Ma tieni presente questo avvertimento dal CharSequencejavadoc: questa interfaccia non affina i contratti generali dei metodi equalse hashCode. Il risultato del confronto tra due oggetti implementati CharSequenceè pertanto, in generale, indefinito . Ogni oggetto può essere implementato da una classe diversa e non vi è alcuna garanzia che ogni classe sarà in grado di testare le sue istanze per la parità con quelle dell'altra. È quindi inappropriato utilizzare CharSequenceistanze arbitrarie come elementi in un set o come chiavi in ​​una mappa.
Trevor Robinson,

3
@Pacerier: penso che sia più una limitazione pratica. CharSequenceera un retrofit in JDK 1.4 per introdurre un'interfaccia comune a scopo limitato per oggetti contenenti sequenze di caratteri. Alcuni di questi oggetti contengono altri stati, quindi potrebbe non avere senso definire Object.equals"contiene la stessa sequenza di caratteri". NIO CharBuffer, ad esempio, espone i personaggi solo tra i suoi positione limitcome i CharSequence, sebbene potenzialmente contenga molti altri personaggi.
Trevor Robinson,

6
@TrevorRobinson, Quindi il bug di progettazione sta avendo equals/ hashCodeon Objectin primo luogo ....
Pacerier

4
@Pacerier: IMHO Non c'è un bug di progettazione in nessuno dei due Objecto CharSequence, non è richiesta alcuna interfaccia per fornire l'equità tra le implementazioni. Non Collectionsono necessari due secondi per fornire la parità tra l' Collectioninterfaccia, ma possono farlo se lo desiderano. L'IMHO CharSequencedovrebbe essere limitato agli input e utilizzato meno per i tipi di ritorno.
Brett Ryan

58

CharSequence= interfaccia
String= implementazione concreta

Tu hai detto:

conversione da uno all'altro

Non c'è conversione da String.

  • Ogni Stringoggetto è a CharSequence.
  • Ogni CharSequencepuò produrre a String. Chiama CharSequence::toString. Se CharSequencesuccede che sia a String, il metodo restituisce un riferimento al proprio oggetto.

In altre parole, ogni Stringè a CharSequence, ma non tutti CharSequencesono a String.

Programmazione su un'interfaccia

Programmando in Android, la maggior parte dei valori di testo è prevista in CharSequence.

Perché? Qual è il vantaggio e quali sono gli impatti principali dell'utilizzo di CharSequence su String?

Generalmente, programmare su un'interfaccia è meglio che programmare su classi concrete. Ciò offre flessibilità, in modo da poter passare da implementazioni concrete di una particolare interfaccia senza rompere altri codici.

Quando si sviluppa un'API per essere utilizzata da vari programmatori in varie situazioni, scrivere il proprio codice per fornire e utilizzare le interfacce più generali possibili. Questo dà al programmatore chiamante la libertà di usare varie implementazioni di quell'interfaccia, qualunque sia la migliore per il loro particolare contesto.

Ad esempio, guarda Java Collections Framework . Se la vostra API dà o prende un insieme ordinato di oggetti, dichiarare i vostri metodi da utilizzare List, piuttosto che ArrayList, LinkedListo qualsiasi altra applicazione di terze parti List.

Quando si scrive un metodo rapido e sporco da utilizzare solo per il codice in un posto specifico, invece di scrivere un'API da utilizzare in più punti, non è necessario preoccuparsi di utilizzare l'interfaccia più generale piuttosto che un concreto specifico classe. Ma anche allora, fa male usare l'interfaccia più generale che puoi.

Quali sono le principali differenze e quali problemi sono previsti, mentre li si utilizza,

  • Con a Stringsai di avere un solo pezzo di testo, interamente in memoria, ed è immutabile.
  • Con a CharSequence, non sai quali potrebbero essere le caratteristiche particolari dell'implementazione concreta.

L' CharSequenceoggetto potrebbe rappresentare un enorme pezzo di testo e quindi ha implicazioni di memoria. Oppure potrebbero essere molti blocchi di testo tracciati separatamente che dovranno essere uniti insieme quando si chiama toStringe quindi hanno problemi di prestazioni. L'implementazione potrebbe persino recuperare il testo da un servizio remoto e pertanto ha implicazioni sulla latenza.

e la conversione da uno all'altro?

In genere non ti convertirai avanti e indietro. A String è a CharSequence. Se il tuo metodo dichiara che richiede un CharSequence, il programmatore chiamante può passare un Stringoggetto o può passare qualcos'altro come un StringBuffero StringBuilder. Il codice del tuo metodo utilizzerà semplicemente tutto ciò che viene passato, chiamando uno dei CharSequencemetodi.

Il risultato più vicino alla conversione è se il codice riceve un CharSequencee sai di aver bisogno di un String. Forse stai interfacciando con il vecchio codice scritto in Stringclasse piuttosto che scritto CharSequencenell'interfaccia. O forse il tuo codice funzionerà intensamente con il testo, ad esempio ripetutamente in loop o analizzando in altro modo. In tal caso, vuoi subire ogni possibile colpo di prestazione una sola volta, quindi chiami toStringin anticipo. Quindi procedi con il tuo lavoro usando quello che sai essere un singolo pezzo di testo interamente in memoria.

Storia contorta

Nota i commenti fatti sulla risposta accettata . L' CharSequenceinterfaccia è stata adattata su strutture di classe esistenti, quindi ci sono alcune sottigliezze importanti ( equals()& hashCode()). Notate le varie versioni di Java (1, 2, 4 e 5) taggate sulle classi / interfacce - un bel po 'di churn nel corso degli anni. Idealmente CharSequencesarebbe stato in atto sin dall'inizio, ma tale è la vita.

Il mio diagramma di classe qui sotto potrebbe aiutarti a vedere il quadro generale dei tipi di stringa in Java 7/8. Non sono sicuro che tutti questi siano presenti in Android, ma il contesto generale potrebbe ancora esserti utile.

diagramma di varie classi e interfacce correlate alle stringhe


2
Hai fatto tu stesso questo diagramma? chiedendosi se esiste un catalogo di questi diagrammi per diverse strutture di dati.
user171943

4
@ user171943 Creato da me, realizzato a mano utilizzando l' app OmniGraffle di OmniGroup.
Basil Bourque,

37

Credo che sia meglio usare CharSequence. Il motivo è che String implementa CharSequence, quindi è possibile passare una stringa in una CharSequence, TUTTAVIA non è possibile passare una CharSequence in una stringa, poiché CharSequence non implementa String. Inoltre, in Android il EditText.getText()metodo restituisce un modificabile, che implementa anche CharSequence e può essere passato facilmente in uno, mentre non facilmente in una stringa. CharSequence gestisce tutto!


7
Puoi farecharSequence.toString()
Jorge Fuentes González il

1
@jorge: Tranne che sarà relativamente inefficiente se la sequenza è mutabile (o per qualsiasi motivo richiede una copia dei caratteri per creare una stringa immutabile).
Lawrence Dol

spiegazione molto bella ..!
majurageerthan,

23

In generale, l'utilizzo di un'interfaccia consente di variare l'implementazione con un danno collaterale minimo. Sebbene java.lang.String sia molto popolare, in alcuni contesti è possibile che si desideri utilizzare un'altra implementazione. Costruendo l'API attorno a CharSequences anziché a String, il codice offre l'opportunità di farlo.


8

Questo è quasi certamente motivi di prestazione. Ad esempio, immagina un parser che passa attraverso un ByteBuffer da 500k contenente stringhe.

Esistono 3 approcci per restituire il contenuto della stringa:

  1. Costruisci una stringa [] al momento dell'analisi, un personaggio alla volta. Questo richiederà un notevole lasso di tempo. Possiamo usare == invece di .equals per confrontare i riferimenti memorizzati nella cache.

  2. Costruisci un int [] con offset al momento dell'analisi, quindi crea dinamicamente String quando si verifica un get (). Ogni stringa sarà un nuovo oggetto, quindi non è possibile memorizzare nella cache valori restituiti e utilizzare ==

  3. Crea una CharSequence [] al momento dell'analisi. Poiché non vengono memorizzati nuovi dati (diversi dagli offset nel buffer dei byte), l'analisi è molto inferiore a quella n. 1. Al momento, non è necessario creare una stringa, quindi ottenere prestazioni è uguale al n. 1 (molto meglio del n. 2), poiché stiamo solo restituendo un riferimento a un oggetto esistente.

Oltre ai guadagni di elaborazione ottenuti con CharSequence, si riduce anche il footprint di memoria non duplicando i dati. Ad esempio, se si dispone di un buffer contenente 3 paragrafi di testo e si desidera restituire tutti e 3 o un singolo paragrafo, sono necessarie 4 stringhe per rappresentarlo. Utilizzando CharSequence è necessario solo 1 buffer con i dati e 4 istanze di un'implementazione CharSequence che tiene traccia dell'inizio e della lunghezza.


6
referenze plz. sembra indovinare a caso cosa sta succedendo. inoltre non trovo valida la tua tesi. si potrebbe semplicemente memorizzare il bytebuffer da 500k come stringa in primo luogo e restituire solo sottostringhe, che è follemente veloce e molto più comune.
kritzikratzi,

6
@kritzikratzi - a partire da JDK7, la sottostringa su String non condivide più l'array sottostante e non è "follemente veloce". Richiede O (N) tempo nella lunghezza della sottostringa e genera una copia dei caratteri sottostanti ogni volta che lo chiami (quindi molta spazzatura).
BeeOnRope,

@kritzikratzi Credo che il motivo della modifica sia che, se la copia non fosse stata creata, la stringa originale verrebbe mantenuta per tutta la durata di tutte le sottostringhe. Dato che le sottostringhe di solito sono solo piccole parti dell'originale e potrebbero durare indefinitamente a seconda del modo in cui vengono utilizzate, ciò comporterebbe spesso ancora più immondizia se le sottostringhe fossero in uso per molto più tempo della stringa originale. Un'alternativa interessante potrebbe essere quella di determinare se copiare o meno in base al rapporto tra sottostringa e dimensione della stringa principale, ma per questo dovresti CharSequenceimplementare la tua implementazione.
JAB

1
Forse ho perso il punto, ma questa risposta non ha senso. A CharSequenceè un'interfaccia : per definizione, non ha nessuno dei dettagli di implementazione discussi perché non ha un'implementazione propria. A Stringè una delle diverse classi concrete che implementano l' CharSequenceinterfaccia. Quindi a String è a CharSequence. È possibile confrontare i dettagli delle prestazioni di Stringvs StringBuffervs StringBuilder, ma non CharSequence. Scrivere "l'elaborazione dei guadagni ottenuti con CharSequence" non ha senso.
Basil Bourque,

7

Un problema che si presenta nel pratico codice Android è che il loro confronto con CharSequence.equals è valido ma non funziona necessariamente come previsto.

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

Il confronto dovrebbe essere effettuato da

("OK").contentEquals(t.GetText()); 

5

CharSequence

A CharSequenceè un'interfaccia, non una classe reale. Un'interfaccia è solo un insieme di regole (metodi) che una classe deve contenere se implementa l'interfaccia. In Android a CharSequenceè un ombrello per vari tipi di stringhe di testo. Ecco alcuni dei più comuni:

(Puoi leggere di più sulle differenze tra questi qui .)

Se hai un CharSequenceoggetto, allora è in realtà un oggetto di una delle classi che implementano CharSequence. Per esempio:

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

Il vantaggio di avere un tipo di ombrello generale come CharSequenceè che puoi gestire più tipi con un solo metodo. Ad esempio, se ho un metodo che accetta un CharSequencecome parametro, potrei passare a Stringo a SpannableStringBuildere gestirà uno dei due.

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

Corda

Si potrebbe dire che a Stringè solo un tipo di CharSequence. Tuttavia, a differenza CharSequence, è una classe reale, quindi puoi ricavarne degli oggetti. Quindi potresti farlo:

String myString = new String();

ma non puoi farlo:

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

Poiché CharSequenceè solo un elenco di regole Stringconformi, è possibile eseguire questa operazione:

CharSequence myString = new String();

Ciò significa che ogni volta che un metodo richiede un CharSequence, va bene dargli un String.

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

// ...

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

Tuttavia, non è vero il contrario. Se il metodo accetta un Stringparametro, non puoi passarlo a qualcosa che è generalmente noto solo come a CharSequence, perché potrebbe effettivamente essere un SpannableStringo qualche altro tipo di CharSequence.

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

// ...

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

0

CharSequenceè un'interfaccia e la Stringimplementa. È possibile creare un'istanza Stringma non è possibile farlo CharSequencepoiché è un'interfaccia. Puoi trovare altre implementazioni nel CharSequencesito Web ufficiale di Java.


-4

CharSequence è una sequenza leggibile di valori char che implementa String. ha 4 metodi

  1. carattere (indice int)
  2. lunghezza()
  3. subSequence (int start, int end)
  4. accordare()

Consultare la documentazione relativa a CharSequence


6
CharSequencenon implementa String. Il contrario è vero, però.
seh

1
Rimuovi questa risposta senza senso
J. Doe il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.