ホームページ Java &#&チュートリアル Java の String、StringBuffer、および StringBuilder クラスのパフォーマンスの詳細な分析

Java の String、StringBuffer、および StringBuilder クラスのパフォーマンスの詳細な分析

Jan 22, 2017 am 11:25 AM

まずは 3 つの特徴を覚えておく必要があります:

String 文字列定数

StringBuffer 文字列変数 (スレッドセーフ)

StringBuilder 文字列変数 (非スレッドセーフ)

1. 定義
API を見ると、 String 、 StringBuffer 、 StringBuilder はすべて CharSequence インターフェイスを実装していることがわかりますが、それらはすべて文字列に関連していますが、その処理メカニズムは異なります。

文字列: 不変の量です。つまり、作成後に変更することはできません。

StringBuffer: String と同様に、メモリに格納される順序付けされた文字列シーケンス (char 型の配列) です。違いは、StringBuffer オブジェクトの値が可変であることです。

StringBuilder: 基本的に StringBuffer クラスと同じですが、どちらも変数文字と文字列シーケンスです。違いは、StringBuffer がスレッドセーフであるのに対し、StringBuilder はスレッドアンセーフであることです。 パフォーマンスの点では、String クラスの操作は新しい String オブジェクトを生成することであり、StringBuilder と StringBuffer は文字配列の単なる展開であるため、String クラスの操作は StringBuffer や StringBuilder よりもはるかに遅くなります。

2. 使用シナリオ
String クラスの使用シナリオ: String クラスは、定数の宣言や少数の変数操作など、文字列が頻繁に変更されないシナリオで使用できます。
StringBuffer クラスを使用するシナリオ: 文字列操作 (スプライシング、置換、削除など) を頻繁に実行し、マルチスレッド環境で実行する場合は、XML 解析、HTTP パラメーター解析、およびカプセル化。
StringBuilder クラスを使用するシナリオ: 文字列操作 (結合、置換、削除など) を頻繁に実行し、シングルスレッド環境で実行する場合は、SQL ステートメントのアセンブル、JSON カプセル化などの StringBuilder の使用を検討できます。 、など。

3. 分析
簡単に言うと、String 型と StringBuffer 型の主なパフォーマンスの違いは、String 型が変更されるたびに、実際には新しい String オブジェクトを生成するのと同じであるということです。次に、ポインタを新しい String オブジェクトにポイントします。したがって、頻繁に内容を変更する文字列には String を使用しないことをお勧めします。オブジェクトが生成されるたびに、特にメモリ内に参照されていないオブジェクトが多すぎると、JVM の GC が開始され、システムのパフォーマンスに影響を及ぼします。動作しますが、速度は間違いなくかなり遅くなります。

StringBuffer クラスを使用する場合、結果は毎回異なります。新しいオブジェクトを生成してオブジェクト参照を変更するのではなく、StringBuffer オブジェクト自体に対する操作になります。したがって、一般に、特に文字列オブジェクトが頻繁に変更される場合には、StringBuffer を使用することをお勧めします。一部の特殊なケースでは、String オブジェクトの文字列連結は、実際には JVM によって StringBuffer オブジェクトの連結として解釈されるため、このような場合、String オブジェクトの速度が StringBuffer オブジェクトの速度よりも遅くなることはなく、特に次の文字列オブジェクトはString S1 オブジェクトの生成速度が単純に速すぎることに驚くでしょう。現時点では、StringBuffer にはまったく利点がありません。スピード。 。実際、これは JVM のトリックであり、JVM から見ると、この

String S1 = “This is only a" + “ simple" + “ test";
StringBuffer Sb = new StringBuilder(“This is only a").append(“ simple").append(“ test");
ログイン後にコピー

は実際には次のようになります。 したがって、もちろん、それほど時間はかかりません。ただし、ここで注意しなければならないのは、文字列が別の String オブジェクトからのものである場合、速度はそれほど速くないということです。 例:

String S1 = “This is only a" + “ simple" + “test";
ログイン後にコピー

このとき、JVM は元の方法で動作します。する。

4. 詳細な JVM 最適化処理

上記のようなパフォーマンスのコストは本当にありますか? 文字列のスプライシングは非常に一般的に使用されていますが、特別な処理の最適化はありませんか? 答えは「はい」です。この最適化は、JVM が .java をコンパイルするときに実行されます。バイトコード。

Java プログラムを実行するには、コンパイル時と実行時の 2 つの期間を経る必要があります。コンパイル中に、Java JVM (コンパイラー) は Java ファイルをバイトコードに変換します。実行時に、Java 仮想マシン (JVM) はコンパイル時に生成されたバイトコードを実行します。この 2 つの期間を通じて、Java はいわゆるコンパイルを 1 か所で実行し、どこでも実行できるようになりました。

コンパイル中に行われる最適化を試して、パフォーマンスに影響を与える可能性のあるコードを作成してみましょう。

String S1 = “This is only a simple test";
ログイン後にコピー

Concatenation.java をコンパイルします。 Concatenation.class を取得します

String S2 = "This is only a";
String S3 = "simple";
String S4 = "test";
String S1 = S2 +S3 + S4;
ログイン後にコピー

次に、javap を使用して、コンパイルされた Concatenation.class ファイルを逆コンパイルします。 javap -c 連結。 javap コマンドが見つからない場合は、javap が存在するディレクトリを環境変数に追加するか、javap へのフルパスを使用することを検討してください。

public class Concatenation {
 public static void main(String[] args) {
   String userName = "Andy";
   String age = "24";
   String job = "Developer";
   String info = userName + age + job;
   System.out.println(info);
 }
}
ログイン後にコピー

このうち、ldc、astoreなどは、アセンブリ命令と同様のJavaバイトコード命令です。次のコメントでは、説明のために Java 関連のコンテンツを使用します。 上記には多くの StringBuilder があることがわかりますが、Java コードでそれらを明示的に呼び出しているわけではありません。これは、JavaJVM が文字列のスプライシングに遭遇すると、StringBuilder オブジェクトを作成します。実際には、StringBuilder オブジェクトの append メソッドを呼び出します。そうすれば、上で心配したような問題はなくなります。

五、仅靠JVM优化?
既然JVM帮我们做了优化,是不是仅仅依靠JVM的优化就够了呢,当然不是。
下面我们看一段未优化性能较低的代码

public void implicitUseStringBuilder(String[] values) {
 String result = "";
 for (int i = 0 ; i < values.length; i ++) {
   result += values[i];
 }
 System.out.println(result);
}
ログイン後にコピー

使用javac编译,使用javap查看

public void implicitUseStringBuilder(java.lang.String[]);
  Code:
    0: ldc      #11         // String
    2: astore_2
    3: iconst_0
    4: istore_3
    5: iload_3
    6: aload_1
    7: arraylength
    8: if_icmpge   38
   11: new      #5         // class java/lang/StringBuilder
   14: dup
   15: invokespecial #6         // Method java/lang/StringBuilder."<init>":()V
   18: aload_2
   19: invokevirtual #7         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22: aload_1
   23: iload_3
   24: aaload
   25: invokevirtual #7         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28: invokevirtual #8         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   31: astore_2
   32: iinc     3, 1
   35: goto     5
   38: getstatic   #9         // Field java/lang/System.out:Ljava/io/PrintStream;
   41: aload_2
   42: invokevirtual #10         // Method java/io/PrintStream.println:(Ljava/lang/String;)V
   45: return
ログイン後にコピー

其中8: if_icmpge 38 和35: goto 5构成了一个循环。8: if_icmpge 38的意思是如果JVM操作数栈的整数对比大于等于(i < values.length的相反结果)成立,则跳到第38行(System.out)。35: goto 5则表示直接跳到第5行。

但是这里面有一个很重要的就是StringBuilder对象创建发生在循环之间,也就是意味着有多少次循环会创建多少个StringBuilder对象,这样明显不好。赤裸裸地低水平代码啊。

稍微优化一下,瞬间提升逼格。

public void explicitUseStringBuider(String[] values) {
 StringBuilder result = new StringBuilder();
 for (int i = 0; i < values.length; i ++) {
   result.append(values[i]);
 }
}
ログイン後にコピー

对应的编译后的信息

public void explicitUseStringBuider(java.lang.String[]);
  Code:
    0: new      #5         // class java/lang/StringBuilder
    3: dup
    4: invokespecial #6         // Method java/lang/StringBuilder."<init>":()V
    7: astore_2
    8: iconst_0
    9: istore_3
   10: iload_3
   11: aload_1
   12: arraylength
   13: if_icmpge   30
   16: aload_2
   17: aload_1
   18: iload_3
   19: aaload
   20: invokevirtual #7         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   23: pop
   24: iinc     3, 1
   27: goto     10
   30: return
ログイン後にコピー

   

从上面可以看出,13: if_icmpge 30和27: goto 10构成了一个loop循环,而0: new #5位于循环之外,所以不会多次创建StringBuilder.

总的来说,我们在循环体中需要尽量避免隐式或者显式创建StringBuilder. 所以那些了解代码如何编译,内部如何执行的人,写的代码档次都比较高。

六、结论
在大部分情况下 StringBuffer > String

Java.lang.StringBuffer是线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。在程序中可将字符串缓冲区安全地用于多线程。而且在必要时可以对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”(累加);而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。

在大部分情况下 StringBuilder > StringBuffer

java.lang.StringBuilder一个可变的字符序列是JAVA 5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步,所以使用场景是单线程。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的使用方法基本相同。

更多详细分析Java中String、StringBuffer、StringBuilder类的性能相关文章请关注PHP中文网!

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

2025年のトップ4 JavaScriptフレームワーク:React、Angular、Vue、Svelte 2025年のトップ4 JavaScriptフレームワーク:React、Angular、Vue、Svelte Mar 07, 2025 pm 06:09 PM

この記事では、2025年の上位4つのJavaScriptフレームワーク(React、Angular、Vue、Svelte)を分析し、パフォーマンス、スケーラビリティ、将来の見通しを比較します。 強力なコミュニティと生態系のためにすべてが支配的なままですが、彼らの相対的なポップ

カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? Mar 17, 2025 pm 05:44 PM

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

node.js 20:キーパフォーマンスが向上し、新機能 node.js 20:キーパフォーマンスが向上し、新機能 Mar 07, 2025 pm 06:12 PM

node.js 20は、V8エンジンの改善、特により速いガベージコレクションとI/Oを介してパフォーマンスを大幅に向上させます。 新機能には、より良いWebセンブリのサポートと洗練されたデバッグツール、開発者の生産性とアプリケーション速度の向上が含まれます。

Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Mar 17, 2025 pm 05:35 PM

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

Iceberg:データレイクテーブルの未来 Iceberg:データレイクテーブルの未来 Mar 07, 2025 pm 06:31 PM

大規模な分析データセットのオープンテーブル形式であるIcebergは、データの湖のパフォーマンスとスケーラビリティを向上させます。 内部メタデータ管理を通じて、寄木細工/ORCの制限に対処し、効率的なスキーマの進化、タイムトラベル、同時wを可能にします

Spring Boot Snakeyaml 2.0 CVE-2022-1471問題修正 Spring Boot Snakeyaml 2.0 CVE-2022-1471問題修正 Mar 07, 2025 pm 05:52 PM

この記事では、リモートコードの実行を可能にする重大な欠陥であるSnakeyamlのCVE-2022-1471の脆弱性について説明します。 Snakeyaml 1.33以降のSpring Bootアプリケーションをアップグレードする方法は、このリスクを軽減する方法を詳述し、その依存関係のアップデートを強調しています

Javaで機能的なプログラミング技術を実装するにはどうすればよいですか? Javaで機能的なプログラミング技術を実装するにはどうすればよいですか? Mar 11, 2025 pm 05:51 PM

この記事では、Lambda式、Streams API、メソッド参照、およびオプションを使用して、機能プログラミングをJavaに統合することを調べます。 それは、簡潔さと不変性を通じてコードの読みやすさと保守性の改善などの利点を強調しています

高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか? 高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか? Mar 17, 2025 pm 05:46 PM

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

See all articles