web-dev-qa-db-fra.com

Différence exacte entre CharSequence et String in java

J'ai lu ceci post précédent . Quelqu'un peut-il dire quelle est la différence exacte entre CharSequence et String, mis à part le fait que String implémente CharSequence = et que String est une séquence de caractères? Par exemple:

CharSequence obj = "hello";
String str = "hello";
System.out.println("output is : " + obj + "  " + str);

Que se passe-t-il quand "hello" est assigné à obj et encore à str?

98
Amith

Différences générales

En plus de l'interface CharSequence , plusieurs classes implémentent l'interface String . Parmi ceux-ci sont

  • StringBuilder pour les séquences de caractères de longueur variable pouvant être modifiées
  • CharBuffer pour les séquences de caractères de bas niveau de longueur fixe pouvant être modifiées

Toute méthode qui accepte un CharSequence peut également fonctionner sur tous ces éléments. Toute méthode n'acceptant que String nécessitera une conversion. Il est donc prudent d’utiliser CharSequence comme type d’argument dans tous les endroits où vous ne vous souciez pas de l’intérieur. Cependant, vous devez utiliser String comme type de retour si vous retournez réellement un String, car cela évite les conversions possibles de valeurs renvoyées si la méthode d'appel nécessite réellement un String.

Notez également que les cartes doivent utiliser String comme type de clé, et non pas CharSequence, car les clés de carte ne doivent pas changer. En d'autres termes, la nature immuable de String est parfois essentielle.

Extrait de code spécifique

En ce qui concerne le code que vous avez collé: compilez-le simplement et jetez un coup d’œil au bytecode de la JVM en utilisant javap -v. Vous remarquerez que obj et str sont des références au même objet constant. Comme String est immuable, ce type de partage est acceptable.

L'opérateur + De String est compilé en tant qu'invocations de divers appels StringBuilder.append. Donc, cela équivaut à

System.out.println(
  (new StringBuilder())
  .append("output is : ")
  .append((Object)obj)
  .append(" ")
  .append(str)
  .toString()
)

Je dois avouer que je suis un peu surpris que mon compilateur javac 1.6.0_33 Compile le + obj En utilisant StringBuilder.append(Object) au lieu de StringBuilder.append(CharSequence). La première implique probablement un appel à la méthode toString() de l'objet, tandis que la seconde devrait être possible de manière plus efficace. D'autre part, String.toString() renvoie simplement le String lui-même, il y a donc peu de pénalité. Donc, StringBuilder.append(String) pourrait être plus efficace d'environ un seul appel de méthode.

97
MvG

tl; dr

L'un est une interface ( CharSequence ), tandis que l'autre est une implémentation concrète de cette interface ( String ).

CharSequence animal = "cat"  // `String` object presented as the interface `CharSequence`.

En tant qu’interface, normalement, CharSequence apparaît plus souvent que String, mais certains historiques tordus l’ont amenée à définir des années après l'implémentation. Ainsi, dans les anciennes API, nous voyons souvent String alors que dans les API plus récentes, nous avons tendance à voir que CharSequence est utilisé pour définir des arguments et des types de retour.

Détails

De nos jours, nous savons qu’en général, une API/un framework devrait se concentrer sur l’exportation d’interfaces principalement et de classes concrètes. Mais nous ne connaissions pas toujours si bien cette leçon.

La classe String est arrivée en premier en Java. Ce n'est que plus tard qu'ils ont placé une interface frontale, CharSequence.

Histoire tordue

Un peu d'histoire pourrait aider à la compréhension.

À ses débuts, Java a été précipité sur le marché un peu en avance sur son temps, en raison de la manie Internet/Web animant le secteur. Certaines bibliothèques n’étaient pas aussi bien pensées qu’elles auraient dû l’être. La manipulation des cordes était l’un de ces domaines.

En outre, Java est l’un des premiers environnements non académiques orientés vers la production programmation orientée objet (OOP) . Le seul succès réussi dans le monde réel, caoutchouc-répond-le implémentations en -road de OOP avant cela était quelques versions limitées de Smalltalk , alors Objective-C avec NeXTSTEP / OpenStep Donc, beaucoup de leçons pratiques restaient à apprendre.

Java a commencé avec la classe String et StringBuffer . Mais ces deux classes étaient indépendantes les unes des autres et n'étaient liées ni par héritage ni par interface. Plus tard, l'équipe Java a reconnu qu'il aurait dû exister un lien unificateur entre les implémentations liées aux chaînes pour les rendre interchangeables. Dans Java 4 l'équipe a ajouté le - CharSequence L’interface a été implémentée rétroactivement sur String et String Buffer, de même que l’ajout d’une autre implémentation CharBuffer . Plus tard dans Java 5 ils ont ajouté StringBuilder , fondamentalement une version non synchronisée et donc un peu plus rapide de StringBuffer.

Ces classes orientées sur les chaînes sont donc un peu un fouillis et un peu déroutant à apprendre. De nombreuses bibliothèques et interfaces ont été construites pour prendre et retourner des objets String. De nos jours, de telles bibliothèques devraient généralement être construites pour s’attendre à CharSequence. Mais (a) String semble toujours dominer l'espace mental, et (b) il peut y avoir quelques problèmes techniques subtils lors du mélange des diverses implémentations CharSequence. Avec la vision rétrospective 20/20, nous pouvons voir que tout ce matériel de cordes aurait pu être mieux géré, mais nous en sommes là.

Idéalement Java aurait démarré avec une interface et/ou une superclasse qui serait utilisée dans de nombreux endroits où nous utilisons maintenant String, tout comme nous utilisons Collection ou List interfaces à la place de ArrayList ou LinkedList implémentations.

Interface ou classe

La principale différence à propos de CharSequence est qu’il s’agit d’un interface , pas d’un implémentation . Cela signifie que vous ne pouvez pas instancier directement un CharSequence. Vous instanciez plutôt l'une des classes qui implémentent cette interface.

Par exemple, ici nous avons x qui ressemble à un CharSequence mais en dessous se trouve un objet StringBuilder.

CharSequence x = new StringBuilder( "dog" );

Cela devient moins évident lorsque vous utilisez un littéral String. Gardez à l'esprit que lorsque vous voyez du code source avec juste des guillemets autour des caractères, le compilateur traduit cela en un objet String.

CharSequence y = "cat";  // Looks like a CharSequence but is actually a String instance.

Il existe des différences subtiles entre "cat" Et new String("cat"), comme indiqué dans cette autre question , mais ne sont pas pertinentes ici.

Diagramme de classe

Ce diagramme de classes peut aider à vous guider. J'ai noté la version de Java) dans laquelle ils semblaient démontrer l'ampleur des changements apportés à ces classes et interfaces.

diagram showing the various string-related classes and interfaces as of Java 8

Blocs de texte

Autre que de plus en plus emoji et les autres personnages fournis avec les versions successives du support nicode , ces dernières années, peu de choses ont changé dans Java = pour travailler avec du texte… jusqu'au Java 13.

Java 13 peut offrir un aperçu de la nouvelle fonctionnalité: des blocs de texte . Cela faciliterait l'écriture de chaînes de code incorporées telles que SQL. Voir JEP 355 .

Cet effort a été précédé de JEP 326: littéraux de chaîne bruts (aperçu) .

85
Basil Bourque

CharSequence est un contrat ( interface ), et String est un implémentation de ce contrat.

public final class String extends Object 
    implements Serializable, Comparable<String>, CharSequence

Le documentation pour CharSequence est:

Une séquence de caractères est une séquence lisible de valeurs de caractères. Cette interface fournit un accès uniforme, en lecture seule, à de nombreux types de séquences de caractères. Une valeur de caractère représente un caractère dans le plan multilingue de base (BMP) ou un substitut. Reportez-vous à Représentation des caractères Unicode pour plus de détails.

21
Francisco Spaeth

autre que le fait que String implémente CharSequence et que String est une séquence de caractères.

Plusieurs choses se passent dans votre code:

CharSequence obj = "hello";

Cela crée un String littéral, "hello", qui est un objet String. Étant un String, qui implémente CharSequence, c'est aussi un CharSequence. (vous pouvez lire cet article sur le codage d'interface par exemple).

La ligne suivante:

String str = "hello";

est un peu plus complexe. String les littéraux dans Java sont détenus dans un pool (interné) de sorte que le "hello" sur cette ligne est le même objet (identité) que le "hello" sur la première ligne. Par conséquent, cette ligne attribue uniquement le même String littéral à str.

À ce stade, obj et str sont des références au String literal "hello" et sont donc equals, == et ils sont à la fois un String et un CharSequence.

Je vous suggère de tester ce code, en montrant à l'action ce que je viens d'écrire:

public static void main(String[] args) {
    CharSequence obj = "hello";
    String str = "hello";
    System.out.println("Type of obj: " + obj.getClass().getSimpleName());
    System.out.println("Type of str: " + str.getClass().getSimpleName());
    System.out.println("Value of obj: " + obj);
    System.out.println("Value of str: " + str);
    System.out.println("Is obj a String? " + (obj instanceof String));
    System.out.println("Is obj a CharSequence? " + (obj instanceof CharSequence));
    System.out.println("Is str a String? " + (str instanceof String));
    System.out.println("Is str a CharSequence? " + (str instanceof CharSequence));
    System.out.println("Is \"hello\" a String? " + ("hello" instanceof String));
    System.out.println("Is \"hello\" a CharSequence? " + ("hello" instanceof CharSequence));
    System.out.println("str.equals(obj)? " + str.equals(obj));
    System.out.println("(str == obj)? " + (str == obj));
}
12
assylias

Je sais que c'est une évidence, mais CharSequence est une interface alors que String est une classe concrète :)

Java.lang.String est une implémentation de cette interface ...

2
Mark Bramnik

Considérons UTF-8. En UTF-8, les points de code Unicode sont construits à partir d'un ou plusieurs octets. Une classe encapsulant un tableau d'octets UTF-8 peut implémenter l'interface CharSequence mais n'est décidément pas une chaîne. Bien sûr, vous ne pouvez pas transmettre un tableau d'octets UTF-8 dans lequel une chaîne est attendue, mais vous pouvez également transmettre une classe wrapper UTF-8 qui implémente CharSequence lorsque le contrat est assoupli pour autoriser une CharSequence. Sur mon projet, je développe une classe appelée CBTF8Field (format de transfert binaire compressé - huit bits) pour la compression de données pour xml et je souhaite utiliser l'interface CharSequence pour implémenter des conversions de tableaux d'octets CBTF8 vers/à partir de tableaux de caractères (UTF-16). ) et des tableaux d'octets (UTF-8).

Je suis venu ici pour comprendre parfaitement le contrat de sous-séquence.

2
Patrick Campbell

À partir de l'API Java de CharSequence :

Une séquence de caractères est une séquence lisible. Cette interface fournit un accès uniforme, en lecture seule, à de nombreux types de séquences de caractères.

Cette interface est ensuite utilisée par String , CharBuffer et StringBuffer pour maintenir la cohérence de tous les noms de méthodes.

1
Andreas Johansson

Dans charSequence, vous n'avez pas de méthodes très utiles disponibles pour String. Si vous ne voulez pas regarder dans la documentation, tapez: obj. et str.

et voyez quelles méthodes votre compilateur vous propose. C'est la différence fondamentale pour moi.

0
Doszi89