Java .equalsメソッドの罠

Javaの.equalsメソッドの罠にひっかかって2週間くらいなやんだのでメモります。
開発してるTwitMorseの逆変換機能の実装の時に直面しました。

equalsメソッドは時折同じ文字列の比較をしてもfalseを返すことがあります。

私が引っかかったコード

protected String convertMorseToText(String text) { 
String[] morse = text.split(" ", 0);
for (String moji : morse) { 
if (moji.equals("--・--")) { 
convertText += moji.replaceAll("--・--", "ア"); 
} 
return convertText; 
}

何をしたかったかというと、
textで入ってきたモールス信号を全角空白で分割し、”ーー・ーー”という文字列があった場合に「ア」に変換して返す
というものでした。

if (moji.equals("--・--")) {

しかし、この一文はfalseとなりスルーされてしまいます。何度”ーー・ーー”を入力しても一致しないものとして処理されていました。
これに2、3週間悩みました。

デバッガで調べていたところどこでfalseになっていたかというと、
Stringクラスのequalsメソッドのある部分でfalseが返されていました。

@Override public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other instanceof String) {
String s = (String)other;
int count = this.count;
if (s.count != count) {
return false;
}
// TODO: we want to avoid many boundchecks in the loop below
// for long Strings until we have array equality intrinsic.
// Bad benchmarks just push .equals without first getting a
// hashCode hit (unlike real world use in a Hashtable). Filter
// out these long strings here. When we get the array equality
// intrinsic then remove this use of hashCode.
if (hashCode() != s.hashCode()) {// ここにひっかかる
return false;
}

どうもhashCodeの違いでequalsを使っても一致しなかったらしい。

そこで以下のように書き換えてみたところうまく機能した。

protected String convertMorseToText(String text) { 
String[] morse = text.split(" ", 0);
for (String moji : morse) { 
String enc = new String(moji);
if (enc.equals("--・--")) { 
convertText += enc.replaceAll("--・--", "ア"); 
} 
return convertText; 
}

入力されたtextを全角空白で分割する所までは一緒。
違いは、新しくencという文字列をmojiを使って生成して比較するという部分でした。
これでhashCodeの違いを解消できました。

equalsメソッドをオーバーライドしたりhashCodeメソッドをオーバーライドしたりという解決方法もあるにはあったのですが、自分はこの方法でequalsメソッドの罠を回避しました。

後学のためにメモとして残しておきます。