• ベストアンサー

Javaの文字列比較

初歩的な質問ですが、Javaで文字列比較は moji == hikaku でなくて moji.equals(hikaku)でないとダメなのでしょうか? 仕様やオブジェクト指向だからでなく、具体的な理由が知りたいです。 数年後には理解できるかもしれませんので難しくても構いません。

  • Java
  • 回答数7
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.6

equals() が内容の比較をすると決まっているわけではなく、各クラスで「うまいこと」再定義されているという方が正確だと思います。 放っておいたら、Object#equals() がそのまま使われて、これは参照値の比較ですよね。 要は演算子 == が Java で再定義できず、一般的な規約としては「参照値の比較です」と == を定義するしかしょうがなかったんだと思います。 == をプログラマが再定義できれば、わざわざ equals() などという演算子を別建てで用意する意味はないと思います。

その他の回答 (6)

  • aton
  • ベストアンサー率47% (160/334)
回答No.7

No.5です。若干訂正します。 訂正前:"=="は名前(参照同一性)の比較,"equals"は内容の比較 訂正後:"=="は名前(参照同一性)の比較,"equals"は(普通は)それ以外(例:内容)の比較 #もちろん,"equals"が特に定義されていない場合は,参照同一性の比較であってもかまわない。 要は,"=="は常に参照同一性の比較に使われ,それ以外に独自の比較方法を定義する場合は"equals"を用いる,という定義で言語としての統一性を保っているということです。 "=="が再定義可能にすると,この統一性は失われます。また場合によっては参照同一性の比較ができなくなります。 なお,ここから先は余談ですが,この問題と,Javaにおいて,高速化のために同一内容のStringは同じインスタンスとして扱うよう内部で実装されていることは,独立と考えます。この話は本質的にJava内部の実装の問題であり,プログラマーから見える界面仕様ではありません。(もちろん,知っておくと処理の高速化を図れたりもしますが。)

  • aton
  • ベストアンサー率47% (160/334)
回答No.5

理由はNo.1~3の方が書かれているとおりですので,私はその一つ先,No.4の方が示された(そして恐らく質問者の方も抱かれるであろう)問題,すなわち,「なぜその2つの方法のうち,Javaの言語設計者は"equals"の方を選んだのか」について私なりの答えを示したいと思います。 要するにこれは,「見た目*だけ*のわかりやすさ」を優先するか,「言語としての統一性を保つことで,言語としてのわかりやすさ」を重視するかというスタンスの違いだと思います。 No.1~3の方が書かれているとおり,簡単に言うと,"=="は名前(識別子)の比較,"equals"は中身の比較です。例えばこれをファイルに喩えてみると,ファイル名(フルパス)が等しいかどうかが前者です。これが同じであれば,同じものを指していることは明らかですから,自動的に中身も等しいと考えられます。一方,ファイル名(フルパス)が異なっていても,ファイルをコピーすれば,同じ内容のファイルを作ることは当然できます。このとき,ファイルの中身を比較するのが,"equals"です。 比較には2種類あり,両方を使い分ける必要があることはこれでわかったかと思います。問題は,ここでStringだけを特別扱いして,"=="で中身の比較を行うという仕様にするかどうか,ということです。 そのようにStringだけを特別扱いすると,見た目上は直観的な記述になります。その代わり,言語としての統一性("=="は名前の比較,"equals"は内容の比較というルール)が崩れます。このルールが崩れると,当然「他にも特別扱いされるクラスがあってもいいんじゃないか」という疑念につながり,「どのクラスでは"=="で内容比較をして,どのクラスではしないのか」ということをいちいち覚える必要が出てきます。こうした混乱を避けるためには,多少見た目がぎこちなくても,統一性を重視する,という立場はあってしかるべきだと考えます。 ちなみに,比較演算子に2種類の表記があり,それぞれに意味が異なる言語は他にもあります。例えばPerlでは,(名前/内容の比較という区別ではありませんが)数値コンテキスト用と文字列コンテキスト用の比較演算子で,振る舞いが違います。 LL言語系の人は,見た目の簡単さ(しばしば syntax sugar と呼ばれるもの)を重視します。たしかにそれは重要なことだと思いますが,言語自体の設計の整合性に混乱を与えるような syntax sugar は,害のほうが大きいというのが私の考えです。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.4

いやいや、まったく尤もな疑問ですね。 Java の実装担当者が寝惚けていたとしか思えませんね。 equals() を使わざるを得ない理由は下で縷々述べられていますが、 どう考えても「文字列として等しい」を普通に == で記述する方が妥当だし、 コードも見易くなることは明らかです。

noname#94983
noname#94983
回答No.3

Javaでは、基本型(intなど)は変数にその値が保管されますが、オブジェクトは「参照(リファレンス)」が保管されます。==は、その変数の値を直接比較します。intなどはそのまま比較されますが、オブジェクトの場合には変数には参照が入っていますから、参照が等しいかどうかを比較するわけです。参照というのは、そのオブジェクトのある場所を示す値と考えてください。 例えば、同じ「A」という値を保持するStringオブジェクトであっても、異なるオブジェクトであれば、異なる場所に保管されますから参照は異なる値になります。従って、trueにはならないのです。 これに対し、equalsは、参照先のオブジェクト自体を比較します(正確にはそのオブジェクトに実装されているequalsメソッドを呼び出して値をチェックします)。だから、オブジェクトどうしの比較はequalsを使うのです。 ただし、リテラル(直接テキストを"Hello"のように書いた値)は、==で比較できます。これは、Javaではリテラルの値は「定数プール」と呼ばれる独自の場所で管理されるためです。例えば、"Hello"というリテラルは、どこで何箇所使われてもすべて定数プール内の同じ"Hello"リテラルを参照します。参照する値がすべて同じなので、==でも等しいと確認できるわけです。

  • auty
  • ベストアンサー率58% (284/486)
回答No.2

>>> Javaで文字列比較は moji == hikaku でなくて moji.equals(hikaku)でないとダメなのでしょうか? ダメです。!! ’比較’が何と何を比較するかを考えて見ましょう。 ・ moji == hikaku の場合      参照を比較する。(ちょうど整数を比較するように)      C言語をご存知ならば、ポインタ(アドレス)を比較する。      結局オブジェクトを比較していることになります。 ・ moji.equals(hikaku) の場合      文字列そのものを比較する。      この場合、文字列は、Stringオブジェクトmoji、hikakuの一部分だと考えてください。 もし、moji == hikakuが成立すれば、全く同じオブジェクトなので当然その一部である文字列も等しくなります。 逆は成り立ちません。 一部が等しくても、すなわち moji.equals(hikaku)が成り立ってもその所有者(オブジェクト)が等しいとは限りません。 簡単な例を挙げてみましょう。 ------------------------------------------------------------ 太郎という名の人(オブジェクト)はたくさんいます。 太郎という名は人(オブジェクト)の一部分です。。 山田太郎は一人しかいないとします。 日本太郎も一人とします、 山田太郎==山田太郎 の場合同一本人ですから当然その文字列「太郎」は同じです。 山田太郎.equals(日本太郎)は、実はその名前(文字列「太郎」)同士を比較して、 true を返します。つまり異なった人でも同じ名前の人がいるわけです。 ------------------------------------------------------------ なお、Stringオブジェクトがそのような文字列の比較をする(equals())のは、オーバーライドして設定しているからです。

  • guppy_i
  • ベストアンサー率50% (1/2)
回答No.1

「==」は、メモリ上のアドレスが等しいかどうかを判定します。 「moji」と「hikaku」に格納した文字列そのものが同じでも、 別々のメモリを確保して文字列を置いているため、「==」では よろしくないということになります。 一方、Stringのメソッド「equals」は、文字列そのものが同じで あるかどうかを判定します。 ちなみに、「moji == hikaku」を実行すると、trueが返ります。 これは、javaが気を利かせてそうなっているだけなので、 (それならいいじゃんと言われそうですが(^^;) オブジェクトの 比較は「equals」メソッドを使ってする癖をつけた方が良いです。 他のクラスをバリバリ使っていくようになると、違いが明確に 理解できるようになると思います。 他のクラス(Vector)での例 import java.util.Vector; public class Test { public static void main(String[] args) { Vector a = new Vector(); Vector b = new Vector(); Object o = new Object(); a.add(o); b.add(o); System.out.println(a == b); // falseと表示されます。 System.out.println(a.equals(b)); // trueと表示されます。 } }

関連するQ&A

  • 文字列の比較

    StringBufferオブジェクトの文字列を比較するときは、どのメソッドを使用すればいいのですか? equalsメソッドは同じオブジェクトかどうかを比較するだけなので使えません。

    • ベストアンサー
    • Java
  • オブジェクトの比較と文字列の比較の違い

    今、基本情報技術者の勉強でJavaを勉強しているのですが、持っているテキストの問題で分からないものがありました。 String str1 = "Hello."; String str2 = "Good, Bye."; String str3 = str1; String str4 = str1 + str2; とすると、 (A)str1 == str2; がfalse (B)str1.equals(str3); がtrue というのは分かるのですが、 (C)str4 == "Hello.Good, bye."; がなぜfalseになるのでしょうか? ==はオブジェクトの比較で、equlasは文字列の比較だと書いているのですが、よく違いが分かりません。 また、 上の4つの処理の後に str3 = "test"; という処理を行っているのですが、このときの状況は、 str1はHello.のままで、 str3のみがtestになっている、と理解したのですがそれで合っているのでしょうか?

    • ベストアンサー
    • Java
  • Javaの文字列の大小比較についてです。

    Javaでは、文字列の大小比較をする時、StringのcompareToを使用しまが… compareToの中の処理は一旦char型に直して、それを比較しているのでしょうか? また、compareToを使用せずに、プログラム内に自分で書いた場合、処理速度は変化ありますか?

    • ベストアンサー
    • Java
  • バイナリ文字列の比較について

    テキストをバイナリで読み込んで文字列を比較する際に 下記のロジックだと2バイトずつ読み込んで比較していくのですが 比較したい文字列が"He"だと合致するのですが1バイトずれの "el"だと合致しません。 ストリーム内の任意の文字列を判定したいときはどのように修正すればよいでしょうか? ----sample.txt--- Hello World!! ---------------- byte[] buf = new byte[2]; FileInputStream in = new FileInputStream("sample.txt"); int b; while ((b = in.read(buf)) != -1) { if ("He".equals(new String(buf))) { System.out.println("HelloのHeはOK"); } if ("el".equals(new String(buf))) { System.out.println("HelloのelはNG"); } }

    • ベストアンサー
    • Java
  • C言語 文字列の比較 compare

    プログラミング初心者です。 60文字以内の文字列を入力して、 大小関係を比較・表示するプログラムなのですが・・ 「AはBより大きい」という結果しか出ません。 どこが間違っているのか、ご指摘お願いしますっ。 #include<stdio.h> int main(void) { char moji1[61]; char moji2[61]; printf("文字列Aを入力===>"); scanf("%60s" ,&moji1); printf("文字列Bを入力===>"); scanf("%60s" ,&moji2); if(moji1-moji2>0){ printf("===AはBより大きい===\n"); } else if(moji1-moji2<0){ printf("===AはBより小さい===\n"); } else if(moji1-moji2==0){ printf("===AとBは等しい===\n"); } return 0; } int compare(char *x, char*y) { while(*x==*y){ if(*x=='\0') return 0; x++; y++; } return (*x-*y); }

  • 文字列の配列の比較

    こんにちは。タイトルどおり簡単な質問なのですが、どうしても確認したいのでお願いします。 とあるメソッドで、2次元配列の中にいくつか大文字のOが入ってるのですが、与えられた配列にOがあればtrueを返し、なければfalseを返します。 public boolean cellAt(int row, int col){ if(space[row][col].equals("O")) return true; else return false; } rowとcolはテストメソッドから値を受け取ります。 これでプログラム自体は動くのですが、WebCatという自動的に採点するものがあるのですが、それによるとエラーがでてしまいます・・・。 どこが違うのかは教えてくれないのですが・・・。 上で間違っているとすれば、文字列の比較くらいしかないんじゃないかと思うのですが、 space[row][col].equals("O") これで比較できますよね? 他のを調べて、if (Arrays.equals(space[row][col], "O"))これを試してもみたのですが、赤線が出てしまって無理でした。 どなたか宜しくお願いします。

  • 文字列の比較について

    BufferedReaderでファイルを読んだのちに、見出しの文字列をカンマで分割して 文字列を比較しようとしています。 ですが、分割すると、文字列が別な文字コードによる表記に変わってしまいます。 なぜでしょうか? また、解決方法などのヒントなどあれば教えてください。 BufferedReader buffReader = new BufferedReader( new FileReader("/home/masa/Desktop/Sample.csv")); String s; int ini=0; int wamei=0; int i=0; while((s = buffReader.readLine())!= null){ String[] str = s.split(",", -1); //System.out.println(s); if (i == 0) { for(int j=0; j<str.length;j++){ System.out.println(String.toString(str)); if(str.equals("五十音")){ini = j;} System.out.println("五十音"+ini); if(str.equals("a")){wamei = j;} System.out.println("和名"+wamei); //System.out.println(j); } } i++;

    • ベストアンサー
    • Java
  • Cに慣れてしまった人、どのようにJAVAを克服しましたか?

    JAVAについて質問です。 私はC言語をこの1年間勉強してきました。 そしてC言語のコーディングの仕方に慣れきってしまったせいか、どうしてもJAVAのオブジェクト指向 というものが理解できません。 コーディングも上手くいきません。 クラスやメソッドやインスタンスがどうとかコンストラクタが・・・などの横文字が全然意味が分かりません。 C言語で言うとどれがどこに当たるのか!? とかいう風に置き換えて考えようとしても上手く行きません。 こういう、横文字が理解できて、オブジェクト指向の考え方に慣れる為にはどのようにしたらいいでしょうか? また、C言語からプログラミングに入って、後からJAVAを勉強する場合、どのような点に気をつければ良いでしょうか? また、JAVAの克服法を教えてください。

    • ベストアンサー
    • Java
  • 文字列比較がどうしてもできません。

    いつもお世話になっております。 現在、Perlの練習を兼ねてCGIによる簡単なスクリプトを作っています。 内容としては、フォームに入力された値を、『name.log』ファイルに書いてある値(名前一覧)を参照して、『hikaku.cgi』で比較し、 一致しなければ、『hikaku.cgi』が「名前がありません」という言葉を返す、というものです。 一応、505エラー等は起きていないのですが、どうしても文字列同士の比較ができないので、投稿しました。 各ファイルはこのような内容です。 『name.log』(604) takeshi masako-nisimura teru009 ....以下、10種ほど似たような物 『hikaku.cgi』(705) #! /usr/local/bin/perl $file = 'name.log'; $sain = 0; #フォームから値を取得する部分(省略) $ck = $FORM{'namae'}; open(DB,$file); @HIKAKU2 = <DB>; close(DB); print "Content-type: text/plain\n\n"; foreach $i (@HIKAKU2) { if($i eq $ck) { $sain++; } } if ($sain != 1) { print "名前がありません"; } __END__ こちらの考えでは、name.logの中で同じ名前はないので、$sainには1しか入らず、 したがって、名前がなかった場合は「名前がありません」が表示されるはずなのですが、どうもそれがうまく動きません。 一応、$sainとフォームデータの$ckがどうなっているか、printで表示させてみたのですが、 $sainは0、$ckは入力したフォームの値がきちんと反映されていました。 初心者ですので、間違ったところが多々あると思いますが、どなたか回答いただけると幸いです。

    • ベストアンサー
    • CGI
  • Javaにおけるオブジェクト指向とは?

    現在Javaを勉強しております。 以前はC言語を勉強しておたのですが、 JavaとCの違いにおいてJavaの特徴としてオブジェクト指向と習いました。 しかしいまいちこのオブジェクト指向を理解できません。 プログラムを一つのまとまりとして考えるというのはどういうことなのでしょうか? 確かにJavaはC言語とは違いいくつかのプログラムからできている (はず?見当違いだったらすみません) C言語が一つの大きなプログラムでできているとすると、 Javaは細かいプログラムの集合体であると私は考えていました。 この細かいプログラムの集合体というのがオブジェクト指向なのでしょうか? 全くの見当違いだったらすみません。 よろしくお願いします。 

    • ベストアンサー
    • Java

専門家に質問してみよう