31

以下のコードでは、文字列リテラルの動作が非常に混乱しています。

ライン 1、ライン 2、ライン 3 はtrueであることは理解できますが、ライン 4 はなぜfalseですか?

両方のハッシュコードを印刷すると、それらは同じです。

class Hello
{
   public static void main(String[] args)
   {
      String hello = "Hello", lo = "lo";
      System.out.print((Other1.hello == hello) + " ");     //line 1
      System.out.print((Other1.hello == "Hello") + " ");   //line 2
      System.out.print((hello == ("Hel"+"lo")) + " ");       //line 3
      System.out.print((hello == ("Hel"+lo)) + " ");         //line 4
      System.out.println(hello == ("Hel"+lo).intern());      //line 5
      System.out.println(("Hel"+lo).hashCode());   //hashcode is 69609650 (machine depedent)
      System.out.println("Hello".hashCode());       //hashcode is same WHY ??.
   }
}

class Other1 { static String hello = "Hello"; }

==参照の等価性をチェックし、リテラルのプールをチェックインすることを知っています。私equals()は正しい方法を知っています。コンセプトを理解したい。

私はすでにこの質問をチェックしましたが、明確に説明されていません。

完全な説明をいただければ幸いです。

4

11 に答える 11

26

タイプのすべてのコンパイル時の定数式Stringは、文字列プールに入れられます。

本質的には、コンパイラーがプログラムを実行せずに (簡単に) の値を「計算」できる場合、Stringそれはプールに入れられます (ルールはそれよりも少し複雑で、いくつかのコーナーケースがあります。リンクを参照してください)。詳細については上記を参照してください)。

これは、1 ~ 3 行目のすべての文字列に当てはまります。

"Hel"+loは非定数変数であるため、コンパイル時の定数式ではありません。lo

String の hashCode はそのコンテンツのみに依存するため、ハッシュ コードは同じです。equals()これはとの契約で必要ですhashCode()

于 2013-05-24T06:51:07.600 に答える
2

実行時に連結によって計算された文字列は新しく作成されるため、区別されます

読むためのリンクは次のとおりです。http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5

于 2013-05-24T06:51:20.197 に答える
2

String オブジェクトは、次の方法で作成できます。

String str = new String("abcd");  // Using the new operator 
                                  // str is assigned with "abcd" value at compile time.

String str="abcd";         // Using string literal
                           // str is assigned with "abcd" value at compile time.

String str="ab" + "cd";    // Using string constant expression.
                           // str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1;    // Using string expression.
                           // str is assigned with "abcd" value at run time only.

ハッシュコードは、String オブジェクトの内容に基づいて実行時にのみ計算されます。

于 2013-05-24T07:29:37.120 に答える
1

これは、このインスタンスのコンパイラが、同じ文字列リテラルを焼き付けることができるほど賢くないためです。

ハッシュコードは、同等の文字列に対して常に同じ値を返す必要があるため (.equals を呼び出すと true が返されます)、同じ結果が返されます。

于 2013-05-24T06:49:04.743 に答える
0

最後に私は答えを知っています!

Java SE 8 仕様セクション 15.21.3 参照等値演算子 == および != ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3 )を参照してください。

== は String 型の参照を比較するために使用できますが、このような等価テストでは、2 つのオペランドが同じ String オブジェクトを参照しているかどうかを判断します。

オペランドが異なる String オブジェクトである場合、同じ文字シーケンスが含まれていても、結果はfalseになります(§3.10.5)。2 つの文字列 s と t の内容は、メソッド呼び出し s.equals(t) によって等しいかどうかをテストできます。

したがって、次のコード:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

3 行目の式 ("Hel"+lo) は、実行時に連結によって計算された新しい文字列を返します。

*実行時に連結によって計算された文字列は、新しく作成されるため、区別されます。( http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634 )

したがって、このコードの結果:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

結果は次のとおりです。

false

なぜなら、

この式の「Hello」オブジェクト:

String hello = "Hello";

および ("Hel"+lo) オブジェクトは次の式で表されます。

System.out.print((hello == ("Hel"+lo)) + " ");

異なりますが、

*どちらも「Hello」という同じシーケンス文字を含んでいます。

*どちらも同じ hashCode を持っています。

*hello.equals(("Hel"+lo)) は true を返します。

于 2015-07-21T15:09:16.993 に答える
0

hashCode は、オブジェクト参照とは何の関係もありません (== チェックは参照コンパレーターです)。hashCode が同じ値を返し、equals 演算子が true を返し、== が false を返す 2 つのオブジェクトを持つことが可能です。これは、それらが 2 つの異なるオブジェクトであるが、同じ値を持つ場合です。

行 4 が false を返す理由は、それが実行時に計算された値であり、したがって異なる参照を持つ別の文字列インスタンスであるためだと思います。

于 2013-05-24T06:50:34.427 に答える
0

文字列リテラルは特別なメモリに保存されます。それらがまったく同じである場合、それらは同じメモリ マップを指します。リテラル文字列を作成しない場合、新しいオブジェクトが作成されるため、そのメモリを指していないため、参照は同じではありません。

intern() メソッドは、仮想マシンにそれをメモリの共有文字列リテラル マップに配置するように指示します。そのため、次にそのリテラルを実行するときに、そこを検索してポイントします。

于 2013-05-24T06:52:44.507 に答える
0

あなたがすでに知っているように...これは単に参照のためです...文字列がプールから来るとき、それは同じ参照を持ちます...しかし、操作を行うと、新しい参照を持つ新しい文字列が生成されます...

プーリングの概念については、このリンクを確認できます

于 2013-05-24T06:45:24.217 に答える
0

次のコードのため

("Hel"+lo)) + " "

に内部的に変換されます

new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()

したがって、さまざまな String インスタンスの助けを借りて、まったく新しい String インスタンスが作成されていることがわかります。そのため、ヒープ内の異なるメモリ位置を指しているため、false になります。

于 2013-05-24T06:48:34.620 に答える
0

System.identityHashCode()これはhashCode()通常、オブジェクトの内部アドレスを整数に変換することによって実装されます。

于 2017-08-31T07:44:50.357 に答える