Pourquoi dans Java vous êtes en mesure d'ajouter des chaînes avec l'opérateur +, lorsque String est une classe? Dans theString.Java
code Je n'ai trouvé aucune implémentation pour cet opérateur. Ce concept viole-t-il l'orientation d'objet?
Regardons les expressions simples suivantes en Java
int x=15;
String temp="x = "+x;
Le compilateur convertit "x = "+x;
En un StringBuilder
en interne et utilise .append(int)
pour "ajouter" l'entier à la chaîne.
Tout type peut être converti en type Conversion chaîne par chaîne.
Une valeur x de type primitif T est d’abord convertie en une valeur de référence, comme si elle était donnée en tant qu’argument à une expression de création d’instance de classe appropriée (§15.9):
- Si T est booléen, utilisez un nouveau booléen (x).
- Si T est char, utilisez le nouveau caractère (x).
- Si T est un octet, un court-circuit ou un int, utilisez le nouvel entier (x).
- Si T est long, alors utilisez new Long (x).
- Si T est float, utilisez new float (x).
- Si T est double, alors utilisez new Double (x).
Cette valeur de référence est ensuite convertie au type Conversion chaîne par chaîne.
Maintenant, seules les valeurs de référence doivent être prises en compte:
- Si la référence est null, elle est convertie en chaîne "null" (four ASCII caractères n, u, l, l).
- Sinon, la conversion est effectuée comme par un appel de la méthode toString de l'objet référencé sans argument; mais si le résultat de l'appel de la méthode toString est null, la chaîne "null" est utilisée à la place.
La méthode toString est définie par la classe primordiale Object (§4.3.2). De nombreuses classes le remplacent, notamment Boolean, Character, Integer, Long, Float, Double et String.
Voir §5.4 pour plus de détails sur le contexte de conversion de chaîne.
Optimisation de la concaténation de chaînes: Une implémentation peut choisir d'effectuer la conversion et la concaténation en une seule étape afin d'éviter de créer puis d'éliminer un objet String intermédiaire. Pour augmenter les performances de la concaténation de chaînes répétée, un compilateur Java peut utiliser la classe StringBuffer ou une technique similaire afin de réduire le nombre d'objets String intermédiaires créés lors de l'évaluation d'une expression.
Pour les types primitifs, une implémentation peut également optimiser la création d'un objet wrapper en convertissant directement un type primitif en chaîne.
La version optimisée ne fera pas d’abord une conversion de chaîne entièrement enveloppée.
Ceci est une bonne illustration d'une version optimisée utilisée par le compilateur, même sans la conversion d'une primitive, dans laquelle vous pouvez voir le compilateur changer des éléments dans un StringBuilder en arrière-plan:
http://caprazzi.net/posts/Java-bytecode-string-concatenation-and-stringbuilder/
Ce code Java:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
Génère ceci - voyez comment les deux styles de concaténation conduisent au même code-octet:
L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2
NEW Java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC Java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL Java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL Java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL Java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3
NEW Java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL Java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL Java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL Java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 4
L4
LINENUMBER 27 L4
RETURN
En regardant l'exemple ci-dessus et la façon dont le code octet basé sur le code source dans l'exemple donné est généré, vous pourrez remarquer que le compilateur a transformé en interne l'instruction suivante.
cip+ciop;
dans
new StringBuilder(cip).append(ciop).toString();
En d'autres termes, l'opérateur +
Dans la concaténation de chaînes est en réalité un raccourci pour l'idiome plus verbeux StringBuilder
.
C’est Java qui vérifie les opérandes de +
_ opérateur. Et basé sur les opérandes, il génère le code octet:
C'est ce que dit Java spec:
Les opérateurs + et
-
s'appellent les opérateurs additifs. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpressionLes opérateurs additifs ont la même priorité et sont associatifs syntaxiquement à gauche (ils se regroupent de gauche à droite). Si le type de l'un des opérandes d'un
+
opérateur estString
, alors l'opération est une concaténation de chaîne.Sinon, le type de chacun des opérandes du
+
l'opérateur doit être un type convertible (§5.1.8) en un type numérique primitif, sinon une erreur de compilation survient.Dans tous les cas, le type de chacun des opérandes du binaire
-
l'opérateur doit être un type convertible (§5.1.8) en un type numérique primitif, sinon une erreur de compilation survient.
Comment la classe String remplace l'opérateur +?
Ce n'est pas. Le compilateur le fait. Strictement parlant, le compilateur surcharge l'opérateur + pour les opérandes String.
Tout d'abord (+) est surchargé et non surchargé
Le langage Java fournit une prise en charge spéciale de l'opérateur de concaténation de chaînes (+), qui a été surchargé pour les objets Java Chaînes.
Si l'opérande du côté gauche est String, cela fonctionne comme une concaténation.
Si l'opérande de gauche est Integer, cela fonctionne comme opérateur d'addition
Le langage Java fournit un support spécial pour l'opérateur de concaténation de chaînes (+) et pour la conversion d'autres objets en chaînes. La concaténation de chaînes est implémentée via StringBuilder
(ou StringBuffer
) classe et sa méthode append
.
La signification de l'opérateur +
Appliquée à String
est définie par le langage, comme tout le monde l'a déjà écrit. Puisque vous ne semblez pas trouver cela suffisamment convaincant, considérez ceci:
Les ints, les floats et les doubles ont tous des représentations binaires différentes, et donc ajouter deux ints est une opération différente, en termes de manipulation de bits, que d'ajouter deux floats: pour ints, vous pouvez ajouter peu à peu, en transportant un bit et en vérifiant le dépassement de capacité; pour les flotteurs, vous devez traiter les mantisses et les exposants séparément.
Donc, en principe, "l'addition" dépend de la nature des objets "ajoutés". Java le définit pour les chaînes ainsi que pour les ints et les floats (longs, doubles, ...)
L'opérateur +
Est généralement remplacé par un StringBuilder
lors de la compilation. Vérifiez ceci réponse pour plus de détails à ce sujet.