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
?
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éesCharBuffer
pour les séquences de caractères de bas niveau de longueur fixe pouvant être modifiéesToute 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.
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.
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.
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
.
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.
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.
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.
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) .
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.
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));
}
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 ...
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.
À 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.
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.