- PR -

IndexOfでindexを取得できません

1
投稿者投稿内容
未記入
会議室デビュー日: 2008/06/30
投稿数: 12
投稿日時: 2008-07-17 11:32
お世話になります。
初心者なので、とても簡単な質問かもしれませんが、
よろしくお願いします。

ListからIndexOfでIndexを取得したいのですが、
うまく取得できずに困っています。
ソースは以下の通りです。
該当箇所は★の部分です。

クラスを格納するListから、クラスでIndexOfしています。

デバッグし、値を監視してみたところ
MstConverter.getKbnMst(methodNm, sdb.getCd())は、
cd=1
nm="ほげ"(id=400)
pcd=0

MstConverter.getKbnMstList(methodNm)のインデックス0には、
cd=1
nm="ほげ"(id=400)
pcd=0

と同一のものが入っている(思っている)のですが、
IndexOfの戻り値は-1です。

どうぞご指摘お願いいたします。

public static List<SearchDetailBean> getOverListByKbn(
SearchDetailForm form,
String mstClsNm,
String methodNm
) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException, ClassNotFoundException, SQLException {

List<SearchDetailBean> list = new ArrayList<SearchDetailBean>();
SearchDetailBean sdb = new SearchDetailBean();
HashMap<Integer, SearchDetailBean> map = new HashMap<Integer, SearchDetailBean>();


//チェックされた項目リストをBeanから取得
Object[] obj = (Object[])form.getClass().getMethod(methodNm).invoke(form);

//ループ用
int cnt = MstConverter.getKbnMstList(methodNm).size();

for(int i = 0; i < obj.length; i++) {
//チェックされた項目のうち、i番目の項目を取得
sdb = (SearchDetailBean)form.getClass().getMethod(methodNm, int.class).invoke(form, i);
//チェックされた項目のi番目の項目が、マスタリストの何番目にあるか
★★★★map.put(MstConverter.getKbnMstList(methodNm).indexOf(MstConverter.getKbnMst(methodNm, sdb.getCd())), sdb);
}
//上で取得した番目の通りにリストを作成//チェックされていない項目の番目にはnewしたものを挿入
for(int i = 0; i < cnt; i++) {
if(map.containsKey(i)) {
list.add(map.get(i));
} else {
list.add(new SearchDetailBean());
}
}

return list;

}

その他ソースに関してのご指摘も歓迎です。
(この書き方はありえないetc)

よろしくお願いいたします。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-07-17 11:57
引用:

未記入さんの書き込み (2008-07-17 11:32) より:
デバッグし、値を監視してみたところ
MstConverter.getKbnMst(methodNm, sdb.getCd())は、
cd=1
nm="ほげ"(id=400)
pcd=0

MstConverter.getKbnMstList(methodNm)のインデックス0には、
cd=1
nm="ほげ"(id=400)
pcd=0

と同一のものが入っている(思っている)のですが、
IndexOfの戻り値は-1です。


「同一のもの」とみなすための同一かどうかの判定の定義が必要ですが、おそらくそれをやっていないためだと思われます。一般に、equals メソッドを定義しなければなりません。(そして通常は hashCode メソッドも必要です。)
未記入
会議室デビュー日: 2008/06/30
投稿数: 12
投稿日時: 2008-07-17 14:23
引用:

unibonさんの書き込み (2008-07-17 11:57) より:
「同一のもの」とみなすための同一かどうかの判定の定義が必要ですが、おそらくそれをやっていないためだと思われます。一般に、equals メソッドを定義しなければなりません。(そして通常は hashCode メソッドも必要です。)



ご返答ありがとうございます。
unibonさんの書き込みを元にさらに調べてみました。

IndexOfがequalsメソッドを使用し判定しているため、
equalsメソッドをオーバーライドし、カスタマイズする必要がある。
このオーバーライドしたときの処理で、
二つのオブジェクトが等しいかどうか判定するために
それぞれのオブジェクトについて、比較するための材料を作成する。
その際に、大概はhashCodeメソッドを使用する。

と解釈しました。

頭を整理するためにも書いてみましたが、この解釈でいいですよね…?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-07-17 20:03
引用:

未記入さんの書き込み (2008-07-17 14:23) より:
IndexOfがequalsメソッドを使用し判定しているため、
equalsメソッドをオーバーライドし、カスタマイズする必要がある。


これは合っています。

引用:

未記入さんの書き込み (2008-07-17 14:23) より:
このオーバーライドしたときの処理で、
二つのオブジェクトが等しいかどうか判定するために
それぞれのオブジェクトについて、比較するための材料を作成する。
その際に、大概はhashCodeメソッドを使用する。


これは読み方によっては正しいと言えますが、たぶん微妙に間違っています。

ちなみに、SearchDetailBean クラスを ArrayList だけに入れて使うならば equals だけあれば良く、hashCode はなくても(でたらめな値を返してもそもそも呼ばれないため)、一応は動きます。
しかし、HashMap の key に入れると hashCode が呼ばれるため、正しい値を返さないと動きが変になります。
hashCode を書くのがめんどくさかったら、とりあえずは、
コード:
public int hashCode() {
    return 0;
}


のように常に同じ値を返すようにすれば、パフォーマンスは悪いですが、正しい動きをします。

Java Solution 会議室を equals と hashCode で検索してみましたが、20件ぐらいしかヒットしないですね。ありふれたものだと思うのですがなぜこれほど少ないのかが不思議です。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2008-07-17 20:57
#ObjectクラスのJavadocってあんまり読まれていないような気がする・・・。

obj1.equals(obj2)とobj1.hashCode() == obj2.hashCode()
が同じになるような実装が望ましいです。

引用:

このオーバーライドしたときの処理で、
二つのオブジェクトが等しいかどうか判定するために
それぞれのオブジェクトについて、比較するための材料を作成する。
その際に、大概はhashCodeメソッドを使用する。


等価性を示すのはequalsであって、hashCodeではありません。
等価性をオーバーライドによって変更する場合は、
hashCodeもオーバーライドして変更するのがあるべき姿です。
そういう意味で、hashCodeメソッドは使用するのではなく、
オーバーライドするというのが正しいです。
未記入
会議室デビュー日: 2008/06/30
投稿数: 12
投稿日時: 2008-07-18 00:17
unibonさん、かつのりさん
ご返答ありがとうございます。
おかげで少しばかりjavaの仕組みの部分から分かってきた気がします。

お二人の書き込みを踏まえて書いてみました。

【SearchDetailBean.java内】
@Override
public boolean equals(Object obj) {

SearchDetailBean sdb = (SearchDetailBean)obj;
if((cd > 0 && cd == sdb.getCd()) || (expKbn > 0 && expKbn == sdb.getExpKbn())) {
return true;
}
return false;
}

@Override
public int hashCode() {

int fig = Integer.toString(expKbn).length();
double def = 1;
for(int i = 0; i < fig; i++) def *= 10;
Double d = (double)cd + ((double)expKbn / def);
return d.hashCode();
}

//SearchDetailBeanで定義しているもの
private int cd;
private String nm;
private int expKbn;
private String expNm;
//以下にゲッターセッターあり

こんな感じで書きました。
このコードについても何かおかしい点があればご指摘いただければ幸いです。

#システム担当が私一人で、
#プログラムがあまりわかっていない状態からのスタートでしたので、
#書き方が変な方向へ行っていないか気になるのです。。。
1

スキルアップ/キャリアアップ(JOB@IT)