web-dev-qa-db-ja.com

比較方法が一般契約に違反しています! Java 7のみ

私はこれがしばらくの間問題であることを知っていて、私が得ることができる以前のすべての答えをチェックしましたが、それでもこれは機能しません。

オブジェクト「乗組員」は、ランクおよびその他のアイテムを持つ乗組員を表します。比較は、int型の値 'assigned_rank'を比較することで行う必要があります。この値が両方のインスタンスで等しい場合、ブール値の 'is_trainer'が違いを生じるはずです。

このメソッドは、Java <7で実行されている限り、うまく機能しました。しかし、Java 7

Java.lang.IllegalArgumentException: Comparison method violates its general contract!
at Java.util.ComparableTimSort.mergeLo(ComparableTimSort.Java:714)
at Java.util.ComparableTimSort.mergeAt(ComparableTimSort.Java:451)
at Java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.Java:376)
at Java.util.ComparableTimSort.sort(ComparableTimSort.Java:182)
at Java.util.ComparableTimSort.sort(ComparableTimSort.Java:146)
at Java.util.Arrays.sort(Arrays.Java:472)
at Java.util.Collections.sort(Collections.Java:155)
at dormas_flightlog.Query.getCrew(Query.Java:714)

以下にソースを示します。潜在的に危険な部分はすでにコメントアウトされていますが、それでも動作しません。

public class crew implements Serializable, Comparable<crew> {

private static final long serialVersionUID = 36L;
private int flightID = 0;
private int assigned_rank = 25;
private boolean is_trainer = false;
...


@Override
public int compareTo(crew him) {

    int myRank = this.getAssigned_rank();
    int hisRank = him.assigned_rank;

    if (this == him) {
        return 0;
    }
    if (myRank > hisRank) {
        return 1;
    }
    if (myRank < hisRank) {
        return -1;
    }
    if (myRank == hisRank) {
//            if (is_trainer && !o.is_trainer) {
//                i = 1;
//            }
//            if (!is_trainer && o.is_trainer) {
//                i = -1;
//            }
//            if (is_trainer && o.is_trainer) {
//                i = 0;
//            }
//            if (!is_trainer && !o.is_trainer) {
//                i = 0;
//            }
        return 0;
    }

    return 0;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 31 * hash + this.assigned_rank;
    hash = 31 * hash + (this.is_trainer ? 1 : 0);
    return hash;
}

@Override
public boolean equals(Object o) {

    if (this == o) {
        return true;
    }


    int myRank = this.getAssigned_rank();
    int hisRank = 0;

    if (o instanceof crew) {
        crew him = (crew) o;
        hisRank = him.assigned_rank;
    } else {
        return false;
    }

    if (myRank > hisRank) {
        return false;
    }
    if (myRank < hisRank) {
        return false;
    }
    if (myRank == hisRank) {
//            if (is_trainer && !o.is_trainer) {
//                i = 1;
//            }
//            if (!is_trainer && o.is_trainer) {
//                i = -1;
//            }
//            if (is_trainer && o.is_trainer) {
//                i = 0;
//            }
//            if (!is_trainer && !o.is_trainer) {
//                i = 0;
//            }
        return true;
    }

    return false;
}

}

Equals()の実装は、この問題を解決するための試みにすぎませんでした。指定された例外は、equals()の有無にかかわらず発生します。 compareToメソッドがどのようにその契約に違反しているかわかりません。どんな助けも大歓迎です。..ある日、このコードはJava 7で動作しなければなりません。

34
user1007068

これを見てください:

から http://www.Oracle.com/technetwork/Java/javase/compatibility-417013.html#source

分野:API:ユーティリティ概要:配列およびコレクションの更新された並べ替え動作でIllegalArgumentExceptionがスローされる場合がある

説明:Java.util.Arrays.sortおよび(間接的に)Java.util.Collections.sortが使用するソートアルゴリズムが置き換えられました。新しいソート実装は、Comparableコントラクトに違反するComparableを検出した場合、IllegalArgumentExceptionをスローする場合があります。以前の実装では、このような状況を静かに無視していました。以前の動作が必要な場合は、新しいシステムプロパティJava.util.Arrays.useLegacyMergeSortを使用して、以前のマージソート動作を復元できます。

非互換性の性質:行動

RFE:6804124

詳細については、バグデータベースを参照してください 参照はこちら

45
naresh

NaNの値をCollections.sort(...)で比較しているだけかもしれませんが、これは私にとって問題であり、compare(obj1, obj2)メソッドを正しく実装していても例外が発生しました。それを確認します!

9
user2224477

Jdk7のバグであるため、このエラーを解決できました。

ここで私は解決策を見つけました:

「比較メソッドはその一般契約に違反しています!」-TimSortとGridLayout

基本的に私は追加する必要がありました

Java_OPTS="$Java_OPTS -Djava.util.Arrays.useLegacyMergeSort=true"

私のボスに

4
cabaji99

残念ながら、Androidで動作するソリューションはありません。 TimSortは、Java 7&8の下に表示されるaddChildrenForAccessibilityに関連するAndroidのViewGroupで深く使用されます。比較にはユーザーコードは含まれません。

他のレポートからは、一般的に行われているように、RelativeLayoutに重複するアイテムがあることに関連しています。たとえば、画像の上に表示されるTextView、または同じ場所にある2つのアイテム。一度に1つだけ表示するように設定します。 https://code.google.com/p/Android/issues/detail?id=559

バグを回避する方法は見つかりませんでした。 -DjavaオプションをAndroid StudioまたはEclipse(少なくとも私が見つけることができる)で設定することはできません。Java 1.6を使用することで動作しますがAmazonの新しいFireタブレットと携帯電話は、他のデバイスよりもこのバグにはるかに敏感であるようです。

噂がありますJava 9は実行時オプションなどの修正がありますが、長年にわたってバグがあったため、これが修正されるのではないかと疑っています。特にOracleとGoogleの間の敵意。はい、おそらくバグはAndroidコードに本当に深くあり、そこで修正する必要があります。10億を超えるデバイスがあるため、すべての実行可能なソリューションではありません既存のデバイス。

0
Frank