Différence exacte entre CharSequence et Ssortingng dans java

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

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

Que se passe-t-il quand “hello” est assigné à obj et à nouveau à str ?

Différences générales

Il existe plusieurs classes qui implémentent l’interface CharSequence dehors de Ssortingng . Parmi ceux-ci sont

  • SsortingngBuilder 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 une CharSequence peut fonctionner sur tous les deux également. Toute méthode qui accepte uniquement une Ssortingng nécessite une conversion. Donc, il est CharSequence utiliser CharSequence comme type d’argument dans tous les endroits où les CharSequence internes ne vous intéressent pas. Toutefois, vous devez utiliser Ssortingng comme type de retour si vous retournez réellement une Ssortingng , car cela évite les conversions possibles des valeurs renvoyées si la méthode appelante nécessite réellement une Ssortingng .

Notez également que les cartes doivent utiliser Ssortingng comme type de clé, pas CharSequence , car les clés de carte ne doivent pas être modifiées. En d’autres termes, la nature immuable de Ssortingng est parfois essentielle.

Extrait de code spécifique

En ce qui concerne le code que vous avez collé: comstackz-le simplement, et regardez le bytecode JVM en utilisant javap -v . Vous remarquerez que les deux obj et str sont des références au même object constant. Comme un Ssortingng est immuable, ce type de partage est correct.

L’opérateur + de Ssortingng est compilé en tant qu’invocations de différents appels SsortingngBuilder.append . Donc c’est équivalent à

 System.out.println( (new SsortingngBuilder()) .append("output is : ") .append((Object)obj) .append(" ") .append(str) .toSsortingng() ) 

Je dois avouer que je suis un peu surpris que mon compilateur javac 1.6.0_33 comstack le + obj utilisant SsortingngBuilder.append(Object) au lieu de SsortingngBuilder.append(CharSequence) . Le premier implique probablement un appel à la toSsortingng() de l’object, alors que le second devrait être possible de manière plus efficace. D’autre part, Ssortingng.toSsortingng() renvoie simplement la Ssortingng elle-même, il y a donc peu de pénalité. Donc, SsortingngBuilder.append(Ssortingng) peut être plus efficace en invoquant une seule méthode.

tl; dr

L’une est une interface ( CharSequence ) tandis que l’autre est une implémentation concrète de cette interface ( Ssortingng ).

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

En tant CharSequence , normalement, le CharSequence serait plus communément vu que Ssortingng , mais une histoire tordue entraînait la définition de l’interface plusieurs années après l’implémentation. Ainsi, dans les API plus anciennes, nous voyons souvent Ssortingng 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

De nos jours, nous soaps qu’en général, une API / framework doit se concentrer sur l’exportation des interfaces principalement et des classes concrètes en second lieu. Mais nous n’avons pas toujours bien compris cette leçon.

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

Histoire tordue

Un peu d’histoire pourrait aider à comprendre.

À ses débuts, Java a été mis 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 réfléchies qu’elles auraient dû l’être. La manipulation des chaînes était l’un de ces domaines.

De plus, Java était l’un des premiers environnements de programmation orientée object (OOP) non académique orientée vers la production. Les seules implémentations réussies de la POO dans le monde réel sur le caoutchouc ont été certaines versions limitées de SmallTalk , puis Objective-C avec NeXTSTEP / OpenStep . Ainsi, de nombreuses leçons pratiques devaient encore être apsockets.

Java a démarré avec la classe Ssortingng et la classe SsortingngBuffer . Mais ces deux classes n’étaient pas liées entre elles par inheritance ou interface. Plus tard, l’équipe Java a reconnu qu’il devait y avoir un lien unificateur entre les implémentations liées aux chaînes pour les rendre interchangeables. Dans Java 4, l’équipe a ajouté l’interface CharSequence et implémenté rétroactivement cette interface sur Ssortingng and Ssortingng Buffer, ainsi que l’ajout d’une autre implémentation CharBuffer . Plus tard dans Java 5, ils ont ajouté SsortingngBuilder , essentiellement une version non synchronisée et donc plus rapide de SsortingngBuffer .

Donc, ces classes à cordes sont un peu désordonnées et un peu compliquées à apprendre. De nombreuses bibliothèques et interfaces ont été créées pour prendre et renvoyer des objects Ssortingng . De nos jours, de telles bibliothèques devraient généralement être construites pour s’attendre à une CharSequence . Mais (a) Ssortingng semble toujours dominer le mindspace, et (b) il peut y avoir des problèmes techniques subtils lors du mélange des différentes implémentations de CharSequence . Avec la vision du recul de 20/20, nous pouvons voir que tous ces trucs de cordes auraient pu être mieux traités, mais nous y voilà.

Idéalement, Java aurait démarré avec une interface et / ou une super-classe qui seraient utilisées dans de nombreux endroits où nous utilisons désormais Ssortingng , tout comme nous utilisons les interfaces Collection ou List à la place des implémentations ArrayList ou LinkedList .

Interface versus classe

La principale différence avec CharSequence est qu’il s’agit d’une interface et non d’une implémentation . Cela signifie que vous ne pouvez pas instancier directement une CharSequence . Au lieu de cela, vous instanciez l’une des classes implémentant cette interface.

Par exemple, ici nous avons x qui ressemble à un CharSequence mais en dessous est en fait un object SsortingngBuilder .

 CharSequence x = new SsortingngBuilder( "dog" ); 

Cela devient moins évident lors de l’utilisation d’un littéral Ssortingng. N’oubliez pas que lorsque vous voyez du code source avec uniquement des guillemets autour des caractères, le compilateur le traduit en object Ssortingng.

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

Il y a quelques différences subtiles entre "cat" et new Ssortingng("cat") comme discuté dans cette autre question , mais ne sont pas pertinentes ici.

Diagramme de classe

Ce diagramme de classe peut vous aider à vous guider. J’ai noté la version de Java dans laquelle ils semblaient montrer à quel point le changement avait traversé ces classes et interfaces.

Diagramme montrant les différentes classes et interfaces liées aux chaînes à partir de Java 8

Littéraux de chaîne bruts

Une future version de Java pourrait recevoir la nouvelle fonctionnalité des littéraux de chaîne bruts . Cela faciliterait l’écriture de chaînes de code intégrées telles que SQL. Voir JEP 326 .

Ce JEP propose un nouveau type de littéral, un littéral de chaîne brut, qui met de côté les échappements Java et les spécifications de terminaison de ligne Java pour fournir des séquences de caractères plus lisibles et maintenables dans de nombreuses circonstances que le littéral de chaîne traditionnel existant.

Pour plus de discussion, voir cet article et voir ce post de Goetz, les littéraux de chaîne bruts – où nous sums, comment nous sums arrivés ici .

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

 public final class Ssortingng extends Object implements Serializable, Comparable, CharSequence 

La documentation de CharSequence est la suivante:

Un CharSequence est une séquence lisible de valeurs de caractère. Cette interface fournit un access 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 à la section Représentation des caractères Unicode pour plus de détails.

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

Plusieurs choses se passent dans votre code:

 CharSequence obj = "hello"; 

Cela crée un littéral Ssortingng , "hello" , qui est un object Ssortingng . En tant que Ssortingng , qui implémente CharSequence , c’est aussi une CharSequence . (vous pouvez lire cet article sur le codage pour l’interface par exemple).

La ligne suivante:

 Ssortingng str = "hello"; 

est un peu plus complexe. Ssortingng littéraux de Ssortingng en Java sont contenus dans un pool (interned), donc le "hello" sur cette ligne est le même object (identité) que le "hello" sur la première ligne. Par conséquent, cette ligne n’affecte que le même littéral Ssortingng à str .

À ce stade, obj et str sont tous deux des références au littéral Ssortingng "hello" et sont donc equals , == et ils sont à la fois une Ssortingng et une CharSequence .

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

 public static void main(Ssortingng[] args) { CharSequence obj = "hello"; Ssortingng 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 Ssortingng? " + (obj instanceof Ssortingng)); System.out.println("Is obj a CharSequence? " + (obj instanceof CharSequence)); System.out.println("Is str a Ssortingng? " + (str instanceof Ssortingng)); System.out.println("Is str a CharSequence? " + (str instanceof CharSequence)); System.out.println("Is \"hello\" a Ssortingng? " + ("hello" instanceof Ssortingng)); 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)); } 

Je sais que c’est une sorte d’évidence, mais CharSequence est une interface alors que Ssortingng est une classe concrète 🙂

java.lang.Ssortingng est une implémentation de cette interface …

Considérez UTF-8. Dans UTF-8, les points de code Unicode sont créés à partir d’un ou plusieurs octets. Une classe encapsulant un tableau d’octets UTF-8 peut implémenter l’interface CharSequence mais ce n’est certainement pas une chaîne. Certes, vous ne pouvez pas passer un tableau d’octets UTF-8 où une chaîne est attendue, mais vous pouvez certainement passer une classe de wrapper UTF-8 qui implémente CharSequence lorsque le contrat est assoupli pour autoriser une CharSequence. Dans mon projet, je développe une classe appelée CBTF8Field (format de transfert binary compressé – huit bits) pour fournir une compression de données pour xml et utiliser l’interface CharSequence pour implémenter des conversions à partir de tableaux ) et des tableaux d’octets (UTF-8).

La raison pour laquelle je suis venu ici était d’avoir une compréhension complète du contrat de sous-séquence.

Depuis l’API Java de CharSequence :

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

Cette interface est ensuite utilisée par Ssortingng , CharBuffer et SsortingngBuffer pour conserver la cohérence de tous les noms de méthode.

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

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