JavaはStringクラスを認識します(文字列の作成、文字列の比較は等しい、文字列定数プール、文字列の不変性の理解)

Stringクラスを理解する

1.文字列を作成します

文字列を作成する一般的な方法
        //方式一
        String str = "hello";
        System.out.println(str);
        //方式二
        String str2 = new String("hello");
        System.out.println(str2);
        //方式三
        char [] value = {
    
    'h','e','l','l','o'};
        String str3 = new String(value);
        System.out.println(str3);

ここに写真の説明を挿入
これら3つのメソッドのメモリレイアウトは
ここに写真の説明を挿入
次のとおりです
。1。 "hello"は文字列リテラル定数であり、型も文字列です
。2。文字列も参照型です。Stringstr= "Hello";このようなコードのメモリレイアウト
ここに写真の説明を挿入
Javaでは次のようになります。配列、文字列、カスタムクラスはすべて参照型です。

Stringは参照型であるため、次のコードの場合

String str1 = "Hello";
String str2 = str1;

メモリレイアウトは次のとおりです。
ここに写真の説明を挿入

現時点では、str1を「world」に「変更」した後、str2は変更されず、まだhelloです。

str1 = "world";
System.out.println(str2);
// 执行结果
Hello

実際、str1 = "world"のようなコードは、文字列の「変更」としてカウントされませんが、str1の参照が新しいStringオブジェクトを指すようにします。
ここに写真の説明を挿入

2.文字列の比較は等しい

2つのint変数がある場合、それらが等しいと判断するには==で実行できます。

str1 = "world";
System.out.println(str2);
// 执行结果
Hello
int x = 10 ;
int y = 10 ;
System.out.println(x == y); 
// 执行结果
true

Stringオブジェクトで==を使用するとどうなりますか?

代码1
String str1 = "Hello";
String str2 = "Hello"; 
System.out.println(str1 == str2); 
// 执行结果
true 

コード1のメモリレイアウト:
ここに写真の説明を挿入
図に示すように、str1とstr2は同じオブジェクトを指しています。このとき、「Hello」などの文字列定数は文字列定数プールにあります。

文字列定数プールについて

「Hello」などの文字列リテラル定数も、格納するために一定量のメモリスペースを必要とします。このような定数には、変更する必要がないという特徴があります(定数)。したがって、コードに複数の参照がある場合は、次のようにする必要があります。使用「Hello」の場合、定数プールのこの場所を直接参照するだけで、「Hello」をメモリに2回格納する必要はありません。

コード2

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 执行结果
false

コード2:メモリレイアウト:
ここに写真の説明を挿入
String str1 = new String( "Hello");によって作成されたStringオブジェクトは
、 "Hello"のコンテンツを格納するヒープ上の別のスペースに相当します。つまり、 "Hello"のコピーが2つあります。メモリ内」。

文字列==比較は、文字列の内容を比較するのではなく、2つの参照が同じオブジェクトを指しているかどうかを比較します。


オブジェクトの比較についてオブジェクト指向プログラミング言語では、オブジェクトの比較、IDの比較、値の比較、型の比較の3つの方法があります。
ほとんどのプログラミング言語では、値の比較と比較に==が使用されます。

ただし、Javaの==はIDを比較するために使用されます。

Javaで文字列の内容比較するには、Stringクラスによって提供されるequalsメソッドを使用する必要あります

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者这样写也行
// 执行结果
true

equalsの使用に関する注意:
2つの文字列strと "Hello"が等しいかどうかを比較してください。

String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));

私は「メソッド2」を使用することを好みます。strがnullになると、メソッド1のコードは例外をスローしますが、メソッド2は例外をスローしません。

String str = null;
// 方式一
System.out.println(str.equals("Hello"));  // 执行结果 抛出 java.lang.NullPointerException 异 常
// 方式二
System.out.println("Hello".equals(str));  // 执行结果 
false

注:「Hello」のようなリテラル定数は基本的にStringオブジェクトであり、equalsやその他のStringオブジェクトメソッドを使用できます。

3.文字列定数プール

上記の例では、Stringクラスの2つのインスタンス化操作、直接割り当てと新しい新しい文字列があります
。a)直接割り当て

String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
String str = null;
// 方式一
System.out.println(str.equals("Hello"));  // 执行结果 抛出 java.lang.NullPointerException 异 常
// 方式二
System.out.println("Hello".equals(str));  // 执行结果 false
String str1 = "hello" ;
String str2 = "hello" ; 
String str3 = "hello" ; 
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true

メモリレイアウト:
ここに写真の説明を挿入
新しいヒープメモリスペースありませんか?
Stringクラスのデザイン
はJVMの下部で共有デザインパターン使用するため、オブジェクトプール(文字列定数プール)は実際にはJVMの下部で自動的に維持されます。
直接割り当てモードを使用してインスタンス化する場合文字列クラスオブジェクトの場合、インスタンス化されたオブジェクト(文字列コンテンツ)はこのオブジェクトプールに自動的に保存されます。
次回も直接割り当てモードを使用してStringオブジェクトを宣言する場合、この時点でオブジェクトプールに指定されたコンテンツがあると、直接参照されます。
そうでない場合は、新しい文字列オブジェクトを作成し、次回使用するためにオブジェクトプールに保存します。
b)コンストラクターの使用コンストラクターを使用して
クラスオブジェクトをインスタンス化するのが標準的な方法です。次の手順を分析します。

String str = new String(“hello”);

ここに写真の説明を挿入

  1. 文字列構築方法を使用すると、2つのヒープメモリスペースが開かれ、ヒープメモリの1つがガベージスペースになります(文字列定数「hello」も匿名オブジェクトです。一度使用すると、使用されなくなります。使用されてガベージスペースになります。JVMによって自動的にリサイクルされます)。
  2. 文字列共有の問題。同じ文字列が複数回保存される可能性があり、スペースの無駄になります。

Stringのinternメソッドを使用して、Stringオブジェクトを文字列定数プールに手動で追加できます。

// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ; 
String str2 = "hello" ; 
System.out.println(str1 == str2); 
// 执行结果
false
    
String str1 = new String("hello").intern() ; 
String str2 = "hello" ; 
System.out.println(str1 == str2); 
// 执行结果
true

ここに写真の説明を挿入
要約すると、通常、直接割り当てを使用してStringオブジェクトを作成します。

4.不変の文字列を理解する

文字列は不変のオブジェクトであり、その内容は変更できません。

Stringクラスの内部実装もchar []に基づいていますが、Stringクラスは内部文字配列を変更するためのsetメソッドなどを提供していません。

このようなコードとそのメモリ分散を感じてください
ここに写真の説明を挿入
。実際、複数の一時オブジェクトが再度開かれ、+ =の後にstrによって出力される結果が変更されましたが、変更されたのはStringオブジェクト自体ではなく、そのstrが参照しています。他のオブジェクト。

したがって、たとえば、既存の文字列str = "Hello"のように文字列を本当に変更する必要があり、それをstr = "hello"に変更したい場合は、どうすればよいでしょうか。

a)一般的な方法:元の文字列を使用して新しい文字列を作成します

String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
// 执行结果
hello

b)特別な方法(オプション):「リフレクション」などの操作を使用すると、カプセル化が解除され、クラス内のプライベートメンバーにアクセスできます(ここでは詳しく説明しません)。

上記は、Stringクラスのいくつかの知識ポイントです。

おすすめ

転載: blog.csdn.net/weixin_44436675/article/details/112848872