回答:
Javaで次の単純な式を見てみましょう
int x=15;
String temp="x = "+x;
コンパイラ"x = "+x;
はStringBuilder
内部的に変換し.append(int)
、文字列に整数を「追加」するために使用します。
文字列変換により、任意の型をString型に変換できます。
プリミティブ型Tの値xは、適切なクラスインスタンス作成式(§15.9)への引数としてそれを与えるかのように、最初に参照値に変換されます。
- Tがブール値の場合は、新しいBoolean(x)を使用します。
- Tがcharの場合、new Character(x)を使用します。
- Tがbyte、short、またはintの場合、new Integer(x)を使用します。
- Tが長い場合は、新しいLong(x)を使用します。
- Tが浮動小数点数の場合、新しいFloat(x)を使用します。
- Tがdoubleの場合は、新しいDouble(x)を使用します。
この参照値は、文字列変換によって文字列型に変換されます。
これで、参照値のみを考慮する必要があります。
- 参照がnullの場合、文字列 "null"(4つのASCII文字n、u、l、l)に変換されます。
- それ以外の場合、変換は、引数なしで参照されるオブジェクトのtoStringメソッドを呼び出したかのように実行されます。ただし、toStringメソッドの呼び出し結果がnullの場合は、代わりに文字列「null」が使用されます。
toStringメソッドは、原始クラスObject(§4.3.2)によって定義されます。多くのクラス、特にBoolean、Character、Integer、Long、Float、Double、Stringがそれをオーバーライドします。
文字列変換コンテキストの詳細については、§5.4を参照してください。
文字列連結の最適化: 中間文字列オブジェクトの作成と破棄を回避するために、実装は1つのステップで変換と連結を実行することを選択できます。繰り返し文字列連結のパフォーマンスを向上させるために、JavaコンパイラはStringBufferクラスまたは同様の手法を使用して、式の評価によって作成される中間のStringオブジェクトの数を減らすことができます。
プリミティブ型の場合、実装は、プリミティブ型から文字列に直接変換することにより、ラッパーオブジェクトの作成を最適化することもできます。
最適化されたバージョンは、実際には最初に完全にラップされた文字列変換を行いません。
これは、プリミティブを変換しなくても、コンパイラーが使用する最適化されたバージョンの良い例です。コンパイラーがバックグラウンドで物事をStringBuilderに変更しているのを見ることができます。
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
この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();
}
これを生成します-2つの連結スタイルがまったく同じバイトコードになる方法を確認してください:
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
上記の例と、特定の例のソースコードに基づくバイトコードがどのように生成されるかを見ると、コンパイラーが次のステートメントを内部的に変換していることがわかります。
cip+ciop;
に
new StringBuilder(cip).append(ciop).toString();
つまり、+
文字列連結の演算子は、より詳細なStringBuilder
イディオムの省略形です。
演算子のオペランドをチェックするのはJavaコンパイラ機能です+
。そして、オペランドに基づいてバイトコードを生成します:
これはJava仕様が言うことです:
演算子+および
-
は、加算演算子と呼ばれます。AdditiveExpression:MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression-MultiplicativeExpression加算演算子は同じ優先順位を持ち、構文的には左結合です(左から右にグループ化されます)。いずれかのオペランドのタイプの場合
+
、オペレータはString
、動作は、文字列連結です。それ以外の場合、演算子の各オペランドの
+
型は、プリミティブ数値型に変換可能な型(§5.1.8)でなければなりません。そうでないと、コンパイル時エラーが発生します。いずれの場合も、2項
-
演算子の各オペランドの型は、プリミティブ数値型に変換可能な型(§5.1.8)である必要があります。そうしないと、コンパイル時エラーが発生します。
まず、(+)はオーバーライドされずにオーバーロードされます
Java言語では、文字列連結演算子(+)が特別にサポートされています。これは、Java文字列オブジェクト用にオーバーロードされています。
左側のオペランドが文字列の場合、連結として機能します。
左側のオペランドが整数の場合、加算演算子として機能します
int
、Javaの通常の規則が適用されます。
誰もがすでに書いているように、+
適用されたときの演算子の意味はString
言語によって定義されます。これは十分説得力があるとは思えないので、これを考慮してください。
int、float、doubleはすべてバイナリ表現が異なるため、2つのfloatを追加するのとは異なり、2つのintを追加することは、ビット操作の点で異なる操作です。浮動小数点数の場合、仮数と指数を別々に扱う必要があります。
したがって、原則として、「追加」は「追加」されるオブジェクトの性質に依存します。Javaは、文字列とintおよびfloat(long、double、...)に対してそれを定義します。
+
オペレータは、通常に置き換えられてStringBuilder
、コンパイル時に。この問題の詳細については、この回答を確認してください。
+
演算子が置き換えられない場合はありますStringBuilder
か?
+
)演算子はJavaの言語機能です。