113 votes

Différence exacte entre CharSequence et String en java

J'ai lu ceci poste précédent . Quelqu'un peut-il dire quelle est la différence exacte entre CharSequence et String est, à part le fait que String met en œuvre 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 ?

12 votes

Cela va vous paraître très "RTFM", mais c'est un conseil honnête : il peut être très intéressant et instructif de regarder le code source de String par vous-même.

1 votes

Où pouvez-vous trouver le code source Java ? Je croyais qu'il était propriétaire ?

4 votes

@aaronsnoswell : OpenJDK est open source. Vous pouvez trouver une version du String classe à hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/6069fe8ffead/src/share/ . Mais même avant cela, les JDKs Sun étaient livrés avec un fichier appelé src.zip qui contenait une grande partie du code source. Il était possible et utile de consulter ce code, mais le modifier était probablement une autre affaire, en termes de licence.

106voto

MvG Points 22342

Différences générales

Il existe plusieurs classes qui implémentent la fonction CharSequence interface en plus String . Parmi ceux-ci, citons

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

Toute méthode qui accepte un CharSequence peut fonctionner sur tous ces éléments aussi bien les uns que les autres. Toute méthode qui n'accepte qu'un String devront être convertis. Ainsi, en utilisant CharSequence en tant que type d'argument dans tous les endroits où vous ne vous souciez pas de l'interne est prudent. Cependant, vous devriez utiliser String comme type de retour si vous retournez réellement un String car cela permet d'éviter d'éventuelles conversions des valeurs renvoyées si la méthode appelante nécessite effectivement un code String .

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

Extrait de code spécifique

Quant au code que vous avez collé, il suffit de le compiler et de jeter un coup d'oeil au bytecode de la JVM en utilisant javap -v . Vous y remarquerez que les deux obj y str sont des références au même objet constant. En tant que String est immuable, ce type de partage est tout à fait acceptable.

En + opérateur de String est compilé comme des invocations de divers StringBuilder.append appels. Il est donc équivalent à

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 fonction toString() de l'objet, alors que la seconde devrait être possible de manière plus efficace. D'autre part, String.toString() renvoie simplement le String lui-même, donc il y a peu de pénalité là. Donc StringBuilder.append(String) pourrait être plus efficace d'environ une invocation de méthode.

100voto

Basil Bourque Points 8938

En résumé

L'une 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`.

Tout comme ArrayList est un List et HashMap est un Map donc aussi String est un CharSequence .

En tant qu'interface, normalement le CharSequence serait plus fréquente que String mais une histoire tordue a fait que l'interface a été définie il y a des années. après la mise en œuvre. Ainsi, dans les anciennes API, on voit souvent String alors que dans les API plus récentes, nous avons tendance à voir CharSequence utilisé pour définir les arguments et les types de retour.

Détails

Aujourd'hui, nous savons qu'en général, une API/un cadre de travail doit se concentrer sur l'exportation d'interfaces en premier lieu et de classes concrètes en second lieu. Mais cette leçon n'a pas toujours été aussi bien connue.

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

Une histoire tordue

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

À ses débuts, Java a été commercialisé un peu avant l'heure, en raison de la manie de l'Internet et du Web qui animait l'industrie. Certaines bibliothèques n'étaient pas aussi bien pensées qu'elles auraient dû l'être. La gestion des chaînes de caractères était l'un de ces domaines.

De plus, Java a été l'une des premières applications non universitaires orientées vers la production. Programmation orientée objet (POO) environnements. Les seules implémentations réussies de la POO dans le monde réel avant cela étaient quelques versions limitées de SmallTalk alors Objectif-C con NeXTSTEP / OpenStep . De nombreux enseignements pratiques restaient donc à tirer.

Java a commencé avec le String et StringBuffer classe. Mais ces deux classes n'étaient pas liées, ni par héritage ni par interface. Plus tard, l'équipe Java a reconnu qu'il aurait dû y avoir un lien unificateur entre les implémentations liées aux chaînes de caractères pour les rendre interchangeables. Dans Java 4, l'équipe a ajouté la classe CharSequence et implémenté rétroactivement cette interface sur String et String Buffer, ainsi qu'ajouté une autre implémentation CharBuffer . Plus tard, dans Java 5, ils ont ajouté StringBuilder qui est essentiellement une version non synchronisée et donc un peu plus rapide de StringBuffer .

Ces classes orientées cordes sont donc un peu confuses et difficiles à appréhender. De nombreuses bibliothèques et interfaces ont été construites pour prendre et retourner String objets. De nos jours, de telles bibliothèques doivent généralement être construites pour s'attendre à ce que CharSequence . Mais (a) String semble toujours dominer l'espace mental, et (b) il peut y avoir des problèmes techniques subtils lorsque l'on mélange les différents types de produits. CharSequence mises en œuvre. Avec la vision 20/20 du recul, nous pouvons voir que toute cette histoire de chaîne aurait pu être mieux gérée, mais nous y sommes.

Idéalement, Java aurait commencé par une interface et/ou une superclasse qui serait utilisée dans de nombreux endroits où nous utilisons aujourd'hui String tout comme nous utilisons le Collection o List à la place de l'interface ArrayList o LinkedList mises en œuvre.

Interface versus classe

La principale différence entre CharSequence est qu'il s'agit d'un interface et non un mise en œuvre . Cela signifie que vous ne pouvez pas instancier directement un CharSequence . Vous instanciez plutôt l'une des classes qui implémente cette interface.

Par exemple, ici nous avons x qui ressemble à un CharSequence mais en dessous, il y a en fait un StringBuilder objet.

CharSequence x = new StringBuilder( "dog" );  // Looks like a `CharSequence` but is actually a `StringBuilder` instance.

Cela devient moins évident lorsqu'on utilise une chaîne littérale. Gardez à l'esprit que lorsque vous voyez du code source avec seulement des guillemets autour des caractères, le compilateur le traduit en un objet String.

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

Littéral contre constructeur

Il y a quelques différences subtiles entre "cat" y new String("cat") tel que discuté dans cette autre question mais ne sont pas pertinents ici.

Diagramme de classe

Ce diagramme de classe peut vous aider à vous orienter. J'ai noté la version de Java dans laquelle ils sont apparus pour montrer à quel point ces classes et interfaces ont évolué.

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

Blocs de texte

À part ajouter plus Unicode personnages, dont une multitude de emoji Ces dernières années, peu de choses ont changé en Java pour le travail avec du texte. Jusqu'à ce que blocs de texte .

Les blocs de texte sont une nouvelle façon de mieux gérer les chaînes de caractères de plusieurs lignes ou de plusieurs pages. Mise en forme des caractères . Cela rendrait l'écriture de chaînes de code intégrées telles que HTML, XML, SQL ou JSON beaucoup plus pratique.

Je cite JEP 378 :

Un bloc de texte est une chaîne de caractères littérale de plusieurs lignes qui évite la plupart des séquences d'échappement, formate automatiquement la chaîne de manière prévisible et permet au développeur de contrôler le format lorsqu'il le souhaite.

La fonction de blocs de texte fait no introduire un nouveau type de données . Les blocs de texte sont simplement une nouvelle syntaxe pour l'écriture d'une String littérale. Un bloc de texte produit un String tout comme la syntaxe littérale conventionnelle. Un bloc de texte produit un String qui est aussi un objet CharSequence comme indiqué ci-dessus.

Exemple SQL

Pour citer à nouveau JSR 378

Utilisation de littéraux de chaîne "unidimensionnels".

String query = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" +
               "WHERE \"CITY\" = 'INDIANAPOLIS'\n" +
               "ORDER BY \"EMP_ID\", \"LAST_NAME\";\n";

Utilisation d'un bloc de texte "bidimensionnel".

String query = """
               SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
               WHERE "CITY" = 'INDIANAPOLIS'
               ORDER BY "EMP_ID", "LAST_NAME";
               """;

Les blocs de texte se trouvent dans Java 15 et plus tard, par JEP 378 : Blocs de texte .

Présenté en avant-première dans Java 13, sous JEP 355 : Blocs de texte (aperçu) . Puis prévisualisé à nouveau dans Java 14 sous JEP 368 : Blocs de texte (deuxième aperçu) .

Cet effort a été précédé par JEP 326 : Littératures de chaînes brutes (Preview) . Les concepts ont été retravaillés pour produire le Blocs de texte à la place.

2 votes

L'ancienne bonne école

1 votes

Génial, j'ai lu certaines de tes autres réponses et je me suis demandé comment ce gars pouvait en savoir autant, toutes sont longues et bien expliquées, as-tu trouvé un moyen de télécharger des informations dans ton cerveau ?)

22voto

Francisco Spaeth Points 10069

CharSequence est un contrat ( interface ), et String est un mise en œuvre du présent contrat.

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

En documentation pour CharSequence est :

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

12voto

assylias Points 102015

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 String objet. Étant un String qui met en œuvre CharSequence il s'agit également d'un CharSequence . (vous pouvez lire ce billet sur le codage de l'interface par exemple).

La ligne suivante :

String str = "hello";

est un peu plus complexe. String En Java, les littéraux sont conservés dans un pool (interné), de sorte que l'utilisateur ne peut pas les utiliser. "hello" sur cette ligne est le même objet (identité) que la "hello" sur la première ligne. Par conséquent, cette ligne n'attribue que le même String littéral à str .

A ce stade, les deux obj y str sont des références à la String littéral "hello" et sont donc equals , == et ils sont tous deux String et un CharSequence .

Je vous propose de tester ce code, en montrant en 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));
}

3voto

Mark Bramnik Points 4472

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X