CharSequence VS String em Java?

421

Ao programar no Android, a maioria dos valores de texto é esperada CharSequence.

Por que é que? Qual é o benefício e quais são os principais impactos do uso CharSequenceexcessivo String?

Quais são as principais diferenças e quais problemas são esperados enquanto os utiliza e converte de um para outro?

e-satis
fonte
1
Respostas melhores podem ser encontradas na diferença exata entre CharSequence e String em java
Suragch

Respostas:

343

Strings são CharSequences , então você pode simplesmente usar Strings e não se preocupar. O Android está apenas tentando ser útil, permitindo que você também especifique outros objetos CharSequence, como StringBuffers.

Zarkonnen
fonte
94
Exceto quando o Android me passa um CharSequence em um retorno de chamada e eu preciso de um String - chame charSeq.toString ().
Martin Konicek 07/07
100
Mas lembre-se dessa ressalva do CharSequencejavadoc: Essa interface não refina os contratos gerais dos métodos equalse hashCode. O resultado da comparação de dois objetos que implementam CharSequenceé, portanto, geralmente indefinido . Cada objeto pode ser implementado por uma classe diferente e não há garantia de que cada classe será capaz de testar suas instâncias quanto à igualdade com as da outra. Portanto, é inadequado usar CharSequenceinstâncias arbitrárias como elementos em um conjunto ou como chaves em um mapa.
Trevor Robinson
3
@ Pacerier: Eu acho que é mais uma limitação prática. CharSequencefoi um retrofit no JDK 1.4 para introduzir uma interface comum de finalidade limitada para objetos contendo seqüências de caracteres. Alguns desses objetos contêm outro estado, portanto, pode não fazer sentido definir Object.equalscomo "contém a mesma sequência de caracteres". A NIO CharBuffer, por exemplo, apenas expõe os caracteres entre positione limitcomo CharSequence, apesar de conter muitos outros caracteres.
Trevor Robinson
6
@TrevorRobinson, assim o bug projeto está tendo equals/ hashCodeon Objectno primeiro lugar ....
Pacerier
4
@Pacerier: IMHO Não existe um bug de design em nenhuma delas , Objectnem em CharSequencenenhuma interface é necessária para garantir a igualdade entre as implementações. Não Collectionsão necessários dois s para fornecer igualdade entre a Collectioninterface, mas eles podem se assim o desejarem. O IMHO CharSequencedeve ser limitado a entradas e usado menos para tipos de retorno.
Brett Ryan #
58

CharSequence= interface
String= implementação concreta

Você disse:

convertendo de um para outro

Não há como converter String.

  • Todo Stringobjeto é um CharSequence.
  • Todo mundo CharSequencepode produzir um String. Ligue CharSequence::toString. Se por CharSequenceacaso for a String, o método retornará uma referência ao seu próprio objeto.

Em outras palavras, cada Stringum é um CharSequence, mas nem todo CharSequenceé um String.

Programação para uma interface

Ao programar no Android, a maioria dos valores de texto é esperada no CharSequence.

Por que é que? Qual é o benefício e quais são os principais impactos do uso de CharSequence sobre String?

Geralmente, programar para uma interface é melhor do que programar para classes concretas. Isso gera flexibilidade, para que possamos alternar entre implementações concretas de uma interface específica sem quebrar outro código.

Ao desenvolver uma API para ser usada por vários programadores em várias situações, escreva seu código para fornecer e receber as interfaces mais gerais possíveis. Isso dá ao programador chamador a liberdade de usar várias implementações dessa interface, o que for melhor para o seu contexto particular.

Por exemplo, veja o Java Collections Framework . Se a sua API dá ou toma uma coleção ordenada de objetos, declarar seus métodos como a utilização List, em vez de ArrayList, LinkedListou qualquer outra aplicação 3-parte de List.

Ao escrever um pequeno método rápido e sujo para ser usado apenas pelo seu código em um local específico, em vez de escrever uma API para ser usada em vários locais, você não precisa se preocupar em usar a interface mais geral em vez de um concreto específico classe. Mas, mesmo assim, é demais usar a interface mais geral possível.

Quais são as principais diferenças e quais problemas são esperados ao usá-los,

  • Com um, Stringvocê sabe que possui um único pedaço de texto, inteiramente na memória e é imutável.
  • Com a CharSequence, você não sabe quais podem ser os recursos específicos da implementação concreta.

O CharSequenceobjeto pode representar um pedaço enorme de texto e, portanto, tem implicações de memória. Ou pode haver muitos pedaços de texto rastreados separadamente que precisarão ser agrupados quando você ligar toStringe, portanto, apresentar problemas de desempenho. A implementação pode até estar recuperando texto de um serviço remoto e, portanto, tem implicações de latência.

e convertendo de um para outro?

Você geralmente não estará convertendo para frente e para trás. A String é a CharSequence. Se o seu método declarar que é necessário a CharSequence, o programador de chamada pode passar um Stringobjeto ou pode passar algo como um StringBufferou StringBuilder. O código do seu método simplesmente usará o que for passado, chamando qualquer um dos CharSequencemétodos.

O mais próximo que você chegaria da conversão é se o seu código receber um CharSequencee você souber que precisa de um String. Talvez você esteja fazendo interface com o código antigo gravado na Stringclasse, em vez de gravado na CharSequenceinterface. Ou talvez seu código funcione intensivamente com o texto, como repetir repetidamente ou analisar de outra forma. Nesse caso, você deseja obter qualquer resultado de desempenho possível apenas uma vez, para ligar toStringcom antecedência. Em seguida, continue seu trabalho usando o que você sabe ser um único pedaço de texto inteiramente na memória.

História distorcida

Observe os comentários feitos na resposta aceita . A CharSequenceinterface foi adaptada às estruturas de classes existentes, portanto, existem algumas sutilezas importantes ( equals()& hashCode()). Observe as várias versões do Java (1, 2, 4 e 5) marcadas nas classes / interfaces - um pouco de agitação ao longo dos anos. O ideal CharSequenceseria estar em vigor desde o início, mas essa é a vida.

Meu diagrama de classes abaixo pode ajudá-lo a ver o panorama geral dos tipos de string no Java 7/8. Não tenho certeza se todos eles estão presentes no Android, mas o contexto geral ainda pode ser útil para você.

diagrama de várias classes e interfaces relacionadas a strings

Basil Bourque
fonte
2
Você mesmo fez esse diagrama? perguntando se existe um catálogo desses diagramas para diferentes estruturas de dados.
user171943
4
@ user171943 Criado por mim, feito à mão usando o aplicativo OmniGraffle do OmniGroup.
Basil Bourque
37

Eu acredito que é melhor usar CharSequence. O motivo é que String implementa CharSequence, portanto, você pode passar uma String para uma CharSequence, no entanto, você não pode passar uma CharSequence para uma String, pois CharSequence não implementa String. TAMBÉM, no Android, o EditText.getText()método retorna um Editável, que também implementa CharSequence e pode ser passado facilmente para um, enquanto não facilmente para uma String. CharSequence lida com todos!

Farsa, falso
fonte
7
Você pode fazercharSequence.toString()
Jorge Fuentes González
1
@jorge: Exceto que será relativamente ineficiente se a sequência for mutável (ou por qualquer motivo exigir uma cópia dos caracteres para criar uma sequência imutável).
Lawrence Dol
explicação muito boa ..!
majurageerthan
23

Em geral, o uso de uma interface permite variar a implementação com o mínimo de danos colaterais. Embora o java.lang.String seja super popular, pode ser possível que, em certos contextos, alguém queira usar outra implementação. Ao criar a API em torno de CharSequences em vez de Strings, o código oferece a oportunidade de fazer isso.

Itay Maman
fonte
8

Este é quase certamente motivos de desempenho. Por exemplo, imagine um analisador que passe por um ByteBuffer de 500k contendo seqüências de caracteres.

Existem 3 abordagens para retornar o conteúdo da string:

  1. Crie uma String [] no momento da análise, um caractere de cada vez. Isso levará um tempo notável. Podemos usar == em vez de .equals para comparar referências em cache.

  2. Crie um int [] com deslocamentos no momento da análise e, em seguida, crie String dinamicamente quando ocorrer um get (). Cada String será um novo objeto, portanto, nenhum cache retornará valores e usar ==

  3. Crie um CharSequence [] no momento da análise. Como nenhum dado novo é armazenado (exceto deslocamentos no buffer de bytes), a análise é muito menor que o número 1. Na hora de obter tempo, não precisamos criar uma String, portanto, obter desempenho é igual a # 1 (muito melhor que # 2), pois estamos retornando apenas uma referência a um objeto existente.

Além dos ganhos de processamento obtidos com o CharSequence, você também reduz o espaço ocupado pela memória ao não duplicar os dados. Por exemplo, se você possui um buffer contendo 3 parágrafos de texto e deseja retornar todos os 3 ou um único parágrafo, precisará de 4 Strings para representar isso. Usando o CharSequence, você só precisa de 1 buffer com os dados e 4 instâncias de uma implementação do CharSequence que rastreie o início e a duração.

Phil Lello
fonte
6
referências plz. parece adivinhar aleatoriamente o que está acontecendo. Também não acho seu argumento válido. pode-se simplesmente armazenar o bytebuffer de 500k como uma string e, em primeiro lugar, retornar substrings, que são loucos, rápidos e muito mais comuns.
Kritzikratzi
6
@kritzikratzi - a partir do JDK7, a substring no String não compartilha mais a matriz subjacente e não é "louca rapidamente". Leva tempo O (N) no comprimento da substring e gera uma cópia dos caracteres subjacentes cada vez que você o chama (portanto, muito lixo).
BeeOnRope 20/09/2013
@kritzikratzi Acredito que o motivo da mudança é que, se a cópia não fosse feita, a String original seria mantida durante toda a vida útil de todas as substrings. Dado que substrings geralmente são apenas pequenas partes do original e podem durar indefinidamente, dependendo de como são usados, isso geralmente resulta em ainda mais lixo se os substrings estiverem em uso por muito mais tempo do que a string original. Uma alternativa interessante pode ser determinar se você deve ou não copiar com base na proporção da substring e o tamanho da string pai, mas você teria que rolar sua própria CharSequenceimplementação para isso.
JAB
1
Talvez eu tenha esquecido o ponto, mas esta resposta não faz sentido. A CharSequenceé uma interface - por definição, ele não possui nenhum dos detalhes de implementação discutidos porque não possui uma implementação própria. A Stringé uma das várias classes concretas que implementam a CharSequenceinterface. Então a String é a CharSequence. Você pode comparar os detalhes de desempenho de Stringvs StringBuffervs StringBuilder, mas não CharSequence. Escrever "ganhos de processamento obtidos com o CharSequence" não faz sentido.
Basil Bourque
7

Um problema que surge no código prático do Android é que compará-los com o CharSequence.equals é válido, mas não necessariamente funciona conforme o esperado.

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

A comparação deve ser feita por

("OK").contentEquals(t.GetText()); 
Cripth
fonte
5

CharSequence

A CharSequenceé uma interface, não uma classe real. Uma interface é apenas um conjunto de regras (métodos) que uma classe deve conter se implementar a interface. No Android, a CharSequenceé um guarda-chuva para vários tipos de cadeias de texto. Aqui estão alguns dos mais comuns:

(Você pode ler mais sobre as diferenças entre elas aqui .)

Se você tem um CharSequenceobjeto, na verdade, é um objeto de uma das classes que implementam CharSequence. Por exemplo:

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

A vantagem de ter um tipo geral de guarda-chuva CharSequenceé que você pode lidar com vários tipos com um único método. Por exemplo, se eu tiver um método que use a CharSequencecomo parâmetro, eu poderia passar umString ou um SpannableStringBuildere ele lidaria com qualquer um deles.

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

Corda

Você poderia dizer que a Stringé apenas um tipo de CharSequence. No entanto, ao contrário CharSequence, é uma classe real, então você pode criar objetos a partir dela. Então você pode fazer isso:

String myString = new String();

mas você não pode fazer isso:

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

Como CharSequenceé apenas uma lista de regras em Stringconformidade, você pode fazer o seguinte:

CharSequence myString = new String();

Isso significa que sempre que um método pede a CharSequence, é bom atribuir a String.

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

// ...

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

No entanto, o oposto não é verdadeiro. Se o método usa um Stringparâmetro, você não pode transmitir algo que geralmente é conhecido como a CharSequence, porque pode ser realmente um SpannableStringou outro tipo de CharSequence.

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

// ...

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

CharSequenceé uma interface e a Stringimplementa. Você pode instanciar um, Stringmas não o pôde fazer, CharSequencepois é uma interface. Você pode encontrar outras implementações no CharSequencesite oficial do Java.

Xiaogang
fonte
-4

CharSequence é uma sequência legível de valores de caracteres que implementa String. tem 4 métodos

  1. charAt (índice int)
  2. comprimento()
  3. subSequence (int start, int end)
  4. para sequenciar()

Consulte a documentação CharSequence

Srinivas Thammanaboina
fonte
6
CharSequencenão implementa String. O contrário é verdade, no entanto.
seh
1
Por favor, remova esta resposta sem sentido
J. Doe