無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

Object#equals()を実装する。

だいぶ前に書いた、オブジェクト比較ユーティリティを使っています。以下はサンプル。

class Kitten {

    // フィールド
    private String name;
    private int age;
    private Kitten[] friends;

    public boolean equals ( Object obj ) {
        if ( obj == null ) { return false; }
        if ( obj instanceof Kitten ) {
            Object[] that = getValues((Kitten) obj);
            return CompareUtil.equalsSeq(that, getValues(this));

            // 親クラスを持つ場合はそちらも比較する。
            // return CompareUtil.equalsSeq(that, getValues(this))
            //   && super.equals( obj );
        }
        return false;
    }
    public int hashCode () {
        return CompareUtil.hashCodeSeq(getValues(this));

        // 親クラスを持つ場合
        // return 31 * CompareUtil.hashCodeSeq(getValues(this))
        //    + super.hashCode();
    }

    // 比較するフィールドを返す関数
    // equals(),hashcode()の比較対象をここに集約する。
    private static Object[] getValues(Kitten v) {
        return new Object[] {
            
            // 比較するフィールド値をここに並べる。
            
            v.name,
            
            // プリミティブ型はObjectに。JDK5からは不要。
            new Integer( v.age ),
            
            // 配列はListやSetにする。
            // 出現順を考慮する場合、List。未考慮でよい場合、Set。
            // friendsは順番未考慮でよいのでSet。
            CompareUtil.toSet( v.friends )
        };
    }
}

比較するフィールドを関数に集約しているので、フィールドを追加した場合の修正が簡単なのがメリット。比較対象フィールドは自分で明示的に設定します。Bean APIで比較対象フィールドを探すという手もありますが、以下を考慮して泥臭いアプローチを採用。

  • 柔軟性 : 比較対象への追加、削除が簡単にできる。
  • 性能: リフレクションAPIは重そう。


ユーティリティの実装は次の通りです。

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * {@link Object}の比較に関する基本メソッドの実装を提供する
 * ユーティリティメソッドライブラリ。
 */
public final class CompareUtil {

    /**
     * 順番を考慮してハッシュコードを計算する。
     * @param vals フィールド値
     * @return ハッシュコード
     */
    public static final int hashCodeSeq(Object[] vals) {
        int hashCode = 1;
        for (int i = vals.length -1; i >= 0; i-- ) {
            hashCode = 31 * hashCode  +
                (vals[i] == null ? 0: vals[i].hashCode());
        }
        return hashCode;
    }

    /**
     * 順番未考慮でハッシュコードを計算する。
     * @param vals フィールド値
     * @return ハッシュコード
     */
    public static final int hashCode(Object[] vals) {
        int hashCode = 1;
        for (int i = vals.length -1; i >= 0; i-- ) {
            hashCode = hashCode  +
                (vals[i] == null ? 0 : vals[i].hashCode());
        }
        return hashCode;
    }

    /**
     * 順番を考慮して配列を比較する。<br/>
     * <ul>
     *  <li>各配列における要素の出現順を考慮する。</li>
     *  <li>要素数を考慮する。</li>
     * </ul>
     * @param a 比較対象
     * @param b 比較対象
     * @return 同じであればtrue
     */
    public static final boolean equalsSeq(Object[] a, Object[] b) {
        //数を比較
        if (a.length != b.length) {
            return false;
        }
        //値を比較
        for (int i = b.length -1; i >= 0; i-- ) {
            if (!(a[i] != null ? a[i].equals(b[i]) : b[i] == null)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 順番未考慮で配列を比較する。<br/>
     * <ul>
     *  <li>各配列における要素の出現順は未考慮。</li>
     *  <li>要素数を考慮する。</li>
     *  <li>各配列中の同一の要素は1つと見なす。</li>
     * </ul>
     * @param a 比較対象
     * @param b 比較対象
     * @return 同じであればtrue
     */
    public static final boolean equals(Object[] a, Object[] b) {
        //数を比較
        if (a.length != b.length) {
            return false;
        }
        //値を比較
        Set sa = toSet(a);
        Set sb = toSet(b);
        boolean res = sa.equals(sb);
        return res;
    }

    /**
     * 比較のため、配列を{@link Set}に格納する。
     * @param a 配列
     * @return 配列を格納した{@link Set}
     */
    public final static Set toSet(Object[] a) {
        if ( a == null ) { return null; }
        Set set = new HashSet();
        for (int i = 0; i < a.length; i++) {
            set.add(a[i]);
        }
        return set;
    }
    /**
     * 比較のため、配列を{@link List}に格納する。
     * @param a 配列
     * @return 配列を格納した{@link List}
     */
    public final static List toList(Object[] a) {
        if ( a == null ) { return null; }
        List list = new ArrayList();
        for (int i = 0; i < a.length; i++) {
            list.add(a[i]);
        }
        return list;
    }
}