Javaチャレンジャー#2:文字列の比較

Javaチャレンジャー#2:文字列の比較



いつものように、コースの開始にはかなり遅れているので、昨日、新しいスレッド「Java Developer」の間で2回目のレッスンを開催しました。 しかし、これは人生のささいなことですが、今のところ、Java Challengersの一連の記事を公開し続けています。







Javaでは、 String



クラスはchar



配列をカプセル化します( 翻訳者のメモ-Java 9では既にbyte



配列になっています。Java9の文字列のコンパクト化を参照
)。 簡単に言えば、 String



は、単語、文、またはその他の構成要素を構成するために使用される文字の配列です。







カプセル化は、オブジェクト指向プログラミングの最も強力な概念の1つです。 カプセル化のおかげで、 String



クラスの仕組みを知る必要はありません。 インターフェースのメソッドを知る必要があるだけです。













JavaのString



クラスを見ると、 char



配列がどのようにカプセル化されているかがわかります。







 public String(char value[]) { this(value, 0, value.length, null); }
      
      





カプセル化をよりよく理解するために、物理オブジェクトであるマシンを想像してください。 車を運転するには、ボンネットの下で車がどのように機能するかを知る必要がありますか? もちろんそうではありませんが、車のインターフェースが何をしているのかを知っておく必要があります:アクセルペダル、ブレーキ、ハンドル。 これらの各インターフェイスは、特定のアクションをサポートしています:加速、ブレーキ、左折、右折。 オブジェクト指向プログラミングでも同じことが言えます。







Java Challengersシリーズの最初の記事はメソッドのオーバーロードに関するもので、 String



クラスで広く使用されています。 オーバーロードにより、クラスが非常に柔軟になります。







 public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {} //    ...
      
      





この記事では、 String



クラスの仕組みを理解しようとする代わりに、その機能とコードでの使用方法を理解するのに役立ちます。







文字列プールとは何ですか?



String



クラスは、おそらくJavaで最も一般的に使用されるクラスです。 String



を使用するたびに動的メモリ(メモリヒープ)に新しいオブジェクトを作成すると、大量のメモリが無駄になります。 文字列プールは、各行の値に対して1つのオブジェクトのみを保存することでこの問題を解決します。







文字列プールの文字列







行プールの行







Duke



およびJuggy



を使用していくつかのString



変数を作成しましたが、2つのオブジェクトのみが作成され、動的メモリ(ヒープ)に格納されます。 証明については、次のコード例を参照してください。 (Javaでは、「 ==



」演算子を使用して2つのオブジェクトを比較し、同じオブジェクトが同じかどうかを判断します。)







 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy);
      
      





2つのString



変数が文字列プール内の同じオブジェクトを指しているため、このコードはtrue



を返します。 それらの意味は同じです。







例外はnew



演算子です。



このコードを見てください。前の例と似ていますが、違いがあります。







 String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke);
      
      





前の例に基づいて、このコードはtrue



を返すと思うかもしれませんが、そうではありません。 new



演算子を追加すると、メモリに新しいString



オブジェクトが作成されます。 したがって、JVMは2つの異なるオブジェクトを作成します。







ネイティブメソッド



Javaのネイティブメソッドは、通常、メモリの管理とパフォーマンスの最適化を目的として、C言語を使用してコンパイルされるメソッドです。


文字列プールとintern()



メソッド



プールに文字列を格納するには、文字列インターンと呼ばれるメソッドが使用されます。







Javadocintern()



メソッドについて教えてくれるのは次のとおりです。







  /** *      . * *   ( )   {@code String}. * *    intern,     , *    {@code String},   *  {@link #equals(Object)},     . * ,   {@code String}   *        {@code String}. * *   ,      {@code s}  {@code t}, * {@code s.intern() == t.intern()}  {@code true} *    ,  {@code s.equals(t)}  {@code true}. * *       . *      3.10.5 The Java™ Language Specification. * * @returns ,         , * , ,       . * * @jls 3.10.5 String Literals */ public native String intern();
      
      





intern()



メソッドは、文字列プールに文字列を格納するために使用されます。 最初に、既存の行がプールに存在するかどうかを確認します。 そうでない場合は、プールに新しい行を作成します。 行プールのロジックは、 Flyweightパターンに基づいています。







次に、 new



を使用して2行を作成するとどうなるかを確認します。







 String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); //    false System.out.println(duke.intern() == duke2.intern()); //    true
      
      





new



キーワードを使用した前の例とは異なり、この場合、比較はtrue



を返しtrue



。 これは、 intern()



メソッドを使用すると、文字列がプール内にあることが保証されるためです。







String



クラスのequals



メソッド



equals()



メソッドは、2つのクラスが同じかどうかを確認するために使用されます。 equals()



Object



クラスに配置されるため、すべてのJavaクラスがそれを継承します。 ただし、 equals()



メソッドは、正しく機能するためにオーバーライドする必要があります。 もちろん、 String



equals()



オーバーライドします。







ご覧ください:







 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; }
      
      





ご覧のとおり、 String



クラスの値は、オブジェクト参照ではなくequals()



を介して比較されます。 オブジェクトへの参照が異なっていても問題ありません。 条件が比較されます。







一般的なString



メソッド



文字列比較の問題を解決する前に知っておく必要があることがもう1つあります。







String



クラスの最も一般的なメソッドを検討してください。







 //         trim() //     substring(int beginIndex, int endIndex) //    length() //  ,     replaceAll(String regex, String replacement) // ,     CharSequence   contains(CharSequences)
      
      





文字列比較の問題を解決する



小さなパズルを解いて、 String



クラスについて学んだことを確認しましょう。







このタスクでは、学習した概念を使用して複数の行を比較します。 以下のコードを見て、各変数result



値を決定できますか?







 public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } }
      
      





結論はどうなりますか?









正解は記事の最後に記載されています。







今何が起こったの? String



動作を理解する



最初の行には以下が表示されます。







 result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1";
      
      





この場合、 trim()



メソッドがスペースを削除すると、 new



演算子を使用してnew



String



が作成されるため、結果はfalse



です。







次に見るもの:







 result += "flexibleCode" == "flexibleCode" ? "2" : "3";
      
      





ここには秘密はありません;行は行プールで同じです。 この比較はtrue



返しtrue









次に、次のものがあります。







 result += new String("doYourBest") == new String("doYourBest") ? "4" : "5";
      
      





new



を使用すると、2つの新しい行が作成され、それらの値が等しいかどうかは関係ありません。 この場合、値が同じであっても比較はfalse



になりfalse









次:







 result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7";
      
      





equals()



メソッドを使用したため、オブジェクトのインスタンスではなく、文字列値が比較されます。







この場合、値が比較されるため、異なるオブジェクトであるかどうかは関係ありません。 結果はtrue



です。







最後に、次のものがあります。







 result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9";
      
      





前に見たように、 intern()



メソッドは文字列を文字列プールに入れます。 両方の行が同じオブジェクトを指しているため、この場合はtrue



です。







一般的な文字列エラー



特に線に同じ値が含まれている場合、2つの線が同じオブジェクトを指しているかどうかを判断するのは困難です。 文字列値が同じであっても、newを使用すると、常にメモリ内に新しいオブジェクトが作成されることに注意してください。







String



メソッドを使用してオブジェクト参照を比較することも難しい場合があります。 特異性は、メソッドが行の何かを変更すると、オブジェクトへの異なる参照が存在することです。







明確にするのに役立ついくつかの例:







 System.out.println("duke".trim() == "duke".trim());
      
      





trim()



メソッドは新しい行を作成しないため、この比較は真になります。







 System.out.println(" duke".trim() == "duke".trim());
      
      





この場合、最初のtrim()



メソッドは新しい行を生成します。メソッドがその仕事をするため、リンクが異なるためです。







最後に、 trim()



が処理を行うと、新しい行が作成されます。







 //   trim   String new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
      
      





文字列について覚えておくべきこと





答え



この問題に対する答えはDです。結論は12568です。







続行するには...








All Articles