web-dev-qa-db-ja.com

Stringクラスは+演算子をどのようにオーバーライドしますか?

なぜJavaでは、Stringがクラスであるときに、+演算子を使用して文字列を追加できますか?theString.Java codeこの演算子の実装は見つかりませんでした。この概念はオブジェクトの方向に違反しますか?

126
Pooya

Javaで次の簡単な式を見てみましょう

_int x=15;
String temp="x = "+x;
_

コンパイラは_"x = "+x;_を内部でStringBuilderに変換し、.append(int)を使用して文字列に整数を「追加」します。

5.1.11。文字列変換

文字列変換により、任意の型をString型に変換できます。

プリミティブ型Tの値xは、適切なクラスインスタンス作成式(§15.9)の引数として指定することにより、最初に参照値に変換されます。

  • Tがブール値の場合、新しいBoolean(x)を使用します。
  • Tがcharの場合、新しいCharacter(x)を使用します。
  • Tがbyte、short、またはintの場合、new Integer(x)を使用します。
  • Tが長い場合は、新しいLong(x)を使用します。
  • Tがfloatの場合、new Float(x)を使用します。
  • Tがdoubleの場合、新しいDouble(x)を使用します。

この参照値は、文字列変換によってString型に変換されます。

参照値のみを考慮する必要があります:

  • 参照がnullの場合、文字列「null」に変換されます(4つのASCII文字n、u、l、l)。
  • それ以外の場合、変換は、引数なしで参照されるオブジェクトのtoStringメソッドの呼び出しによるかのように実行されます。ただし、toStringメソッドの呼び出し結果がnullの場合、代わりに文字列「null」が使用されます。

ToStringメソッドは、原始クラスObject(§4.3.2)によって定義されます。多くのクラス、特にブール値、文字、整数、Long、Float、Double、およびStringをオーバーライドします。

文字列変換コンテキストの詳細については、5.4を参照してください。

15.18.1。

文字列連結の最適化:実装では、中間文字列オブジェクトの作成と破棄を回避するために、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イディオムの短縮形です。

154
Lion

+演算子のオペランドをチェックするJavaコンパイラー機能です。オペランドに基づいて、バイトコードを生成します。

  • 文字列の場合、文字列を連結するコードを生成します
  • 数字の場合、数字を追加するコードを生成します。

これはJava specが言うこと

演算子+および-は、加法演算子と呼ばれます。 AdditiveExpression:MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression-MultiplicativeExpression

加法演算子は同じ優先順位を持ち、構文的に左結合的です(左から右にグループ化されます)。 +演算子のいずれかのオペランドのタイプがStringの場合、操作は文字列連結です。

それ以外の場合、+演算子の各オペランドの型は、プリミティブ数値型に変換可能な型(§5.1.8)である必要があります。そうしないと、コンパイル時エラーが発生します。

あらゆる場合において、バイナリ-演算子の各オペランドの型は、プリミティブ数値型に変換可能な型(§5.1.8)である必要があります。そうでない場合、コンパイル時エラーが発生します。

27
Ramesh PVK

Stringクラスが+演算子をオーバーライドする方法

そうではありません。コンパイラがそれを行います。厳密に言えば、コンパイラオーバーロード Stringオペランドの+演算子。

14
user207421

まず、(+)はオーバーライドされずにオーバーロードされます

Java言語は、Java Stringsオブジェクトに対してオーバーロードされた文字列連結演算子(+)の特別なサポートを提供します。

  1. 左側のオペランドが文字列の場合、連結として機能します。

  2. 左側のオペランドが整数の場合、加算演算子として機能します

6
Pramod Kumar

Java言語は、文字列連結演算子(+)および他のオブジェクトの文字列への変換の特別なサポートを提供します。文字列連結は、StringBuilder(またはStringBuffer)クラスとそのappendメソッド。

4
Jigar Pandya

Stringに適用される+演算子の意味は、誰もがすでに書いているように、言語によって定義されています。これが十分に納得できるとは思えないので、これを考慮してください。

Int、float、doubleはすべて異なるバイナリ表現を持っているため、2つのintを追加することは、ビット操作の観点から、2つのfloatを追加することとは異なる操作です。フロートの場合、仮数と指数を別々に処理する必要があります。

したがって、原則として、「追加」は「追加される」オブジェクトの性質に依存します。 Javaは、文字列だけでなく、intおよびfloat(long、double、...)

4
alexis

+演算子は通常、コンパイル時にStringBuilderに置き換えられます。これを確認してください answer 詳細については。

3
Scorpio