39

Java で文字列を空の文字列と比較することについて質問があります。またはを使用して文字列を空の文字列と比較すると、違いはあります==equals? 例えば:

String s1 = "hi";

if (s1 == "")

また

if (s1.equals("")) 

equals文字列 (および一般的なオブジェクト) を, ではなくと比較する必要があることはわかっています==が、空の文字列にとって重要かどうか疑問に思っています。

4

8 に答える 8

76
s1 == ""

オブジェクトの等価性ではなく参照の等価性をテストするため、信頼できません (また、String は厳密には標準的ではありません)。

s1.equals("")

の方が優れていますが、null ポインター例外が発生する可能性があります。さらに良いのは:

"".equals(s1)

null ポインター例外はありません。

編集:わかりました、ポイントはcanonical formについて尋ねられました。この記事では、次のように定義しています。

等価関係を持つオブジェクトの集合 S があるとします。標準形式は、S のいくつかのオブジェクトを「標準形式」に指定することによって与えられます。これにより、検討中のすべてのオブジェクトが標準形式の 1 つのオブジェクトと等価になります。

実用的な例を挙げると、有理数の集合を取り上げます (または、「分数」は一般的に呼ばれます)。有理数は、分子と分母 (除数) で構成され、どちらも整数です。これらの有理数は同等です。

3/2、6/4、24/16

有理数は通常、gcd (最大公約数) が 1 になるように記述されます。したがって、それらはすべて 3/2 に単純化されます。3/2 は、この有理数の集合の正規形と見なすことができます。

では、「標準形式」という用語が使用されるとき、それはプログラミングで何を意味するのでしょうか? それはいくつかのことを意味します。たとえば、次の架空のクラスを考えてみましょう。

public class MyInt {
  private final int number;

  public MyInt(int number) { this.number = number; }
  public int hashCode() { return number; }
}

クラス MyInt のハッシュ コードは、そのクラスの標準的な形式です。これは、MyInt のすべてのインスタンスのセットに対して、任意の 2 つの要素 m1 と m2 を取得でき、それらが次の関係に従うためです。

m1.equals(m2) == (m1.hashCode() == m2.hashCode())

その関係こそが、正規形の本質です。これが発生するより一般的な方法は、次のようなクラスでファクトリ メソッドを使用する場合です。

public class MyClass {
  private MyClass() { }

  public MyClass getInstance(...) { ... }
}

コンストラクターはプライベートであるため、インスタンスを直接インスタンス化することはできません。これは単なるファクトリーメソッドです。ファクトリ メソッドでできることは、次のようなことです。

  • 常に同じインスタンス (抽象化されたシングルトン) を返します。
  • 呼び出しごとに新しいインスタンスを作成するだけです。
  • オブジェクトを正規の形式で返します(これについては後で詳しく説明します)。また
  • 君が好きなものならなんでも。

基本的に、ファクトリ メソッドはオブジェクトの作成を抽象化します。個人的には、このパターンの使用を強制するためにすべてのコンストラクターを強制的にプライベートにすることは興味深い言語機能だと思いますが、余談になります。

このファクトリ メソッドでできることは、作成したインスタンスをキャッシュして、任意の 2 つのインスタンス s1 と s2 が次のテストに従うようにすることです。

(s1 == s2) == s1.equals(s2)

したがって、 String が厳密に正規化されていないと言うとき、それは次のことを意味します。

String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true

しかし、他の人が指摘しているように、次を使用してこれを変更できます。

String s3 = new String("blah");

そしておそらく:

String s4 = String.intern("blah");

したがって、参照の等価性に完全に依存することはできないため、まったく依存しないでください。

上記のパターンの警告として、プライベート コンストラクターとファクトリ メソッドを使用してオブジェクトの作成を制御しても、シリアル化のために参照の等価性がオブジェクトの等価性を意味することは保証されないことを指摘しておく必要があります。シリアル化は、通常のオブジェクト作成メカニズムをバイパスします。Josh Bloch は、Effective Java でこのトピックを取り上げています (最初の版では、後に Java 5 の言語機能になった型安全な列挙型パターンについて話しました)。(プライベート) readResolve() メソッドをオーバーロードすることで回避できます。しかし、それはトリッキーです。クラスローダーも問題に影響します。

とにかく、それは正規形です。

于 2009-02-10T10:51:51.940 に答える
28

文字列がリテラルかどうかによって異なります。で文字列を作成する場合

new String("")

次に示すように、等号演算子と "" が一致することはありません。

    String one = "";
    String two = new String("");
    System.out.println("one == \"\": " + (one == ""));
    System.out.println("one.equals(\"\"): " + one.equals(""));
    System.out.println("two == \"\": " + (two == ""));
    System.out.println("two.equals(\"\"): " + two.equals(""));

--

one == "": true
one.equals(""): true
two == "": false
two.equals(""): true

基本的に、常に equals() を使用したい

于 2009-02-10T10:20:01.837 に答える
9
"".equals(s)

最良の選択肢のようですがStringutils.isEmpty(s)、Apache commons lang ライブラリにも含まれています。

于 2009-02-10T10:54:32.310 に答える
6

空の文字列であるかどうかに関係なく、文字列は文字列です。を使用しequals()ます。

于 2009-02-10T10:23:24.623 に答える
4

null チェックが必要な場合は、 String.isEmpty()またはStringUtils.isEmpty(String str)を使用します。

于 2010-12-21T10:36:04.530 に答える
0

与えられた 2 つの文字列:

String s1 = "abc";
String s2 = "abc";

-また -

String s1 = new String("abc");
String s2 = new String("abc");

2 つのオブジェクトに対して実行される == 演算子は、オブジェクトの同一性をチェックします (2 つの演算子が同じオブジェクト インスタンスに戻る場合は true を返します)。 java.lang.Strings に適用される == の実際の動作は、ストリングインターン。

Java では、文字列は(少なくとも部分的には JVM の裁量で)インターンされます。任意の時点で、s1 と s2 は同じオブジェクト参照になるようにインターンされている場合とされていない場合があります (それらが同じ値を持っていると仮定します)。s1 == s2s1 と s2 の両方が抑留されているかどうかのみに基づいて、true を返す場合と返さない場合があります。

s1 と s2 を空の文字列に等しくしても、これには影響しません。それらはまだインターンされている場合とされていない場合があります。

つまり、s1 と s2 の内容が同じ場合、== は true を返す場合と返さない場合があります。s1.equals(s2) は、s1 と s2 の内容が同じ場合に true を返すことが保証されています。

于 2009-02-11T01:26:53.227 に答える