4

キーと値の2つのメンバーを持つ汎用のPairクラスを作成したいと思います。このクラスの唯一の要件は、キーと値の両方がComparableインターフェイスを実装する必要があることです。そうでない場合、Pairクラスはそれらを型パラメーターとして受け入れません。
まず、次のようにコーディングします。

public class Pair<T1 extends Comparable, T2 extends Comparable>

ただし、JDK1.6コンパイラはこれに関する警告を生成します。

Comparable is a raw type. References to generic type Comparable<T> should be parameterized

次に、型パラメーターを追加しようとしましたが、コードは次のようになりました。

public class Pair<T1 extends Comparable<? extends Object>,
                  T2 extends Comparable<? extends Object>>

これで、Pairのコンパレータを生成しようとするまで、すべてがうまくいきます(次のコードはPairクラスにあります)

public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            *first.getKey().compareTo(second.getKey());*
            return 0;
        }
    };

コードfirst.getKey().compareTo(second.getKey());は次のようなエラーを生成します:

The method compareTo(capture#1-of ? extends Object) in the type Comparable<capture#1-of ? extends Object> is not applicable for the  arguments (T1)

このエラーメッセージの意味を知っている人はいますか?
このトピックに関するヒントは大歓迎です。

更新:
完全なコードは次のとおりです。

public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>> {
    private T1 key;
    private T2 value;

    public static int ascending = 1;
    public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            int cmp = first.getKey().compareTo((T1)(second.getKey()));
            if (cmp > 0)  return ascending;
            return -ascending;
        }
    };
}

@MarvinLabsコンパイラがオブジェクトが同じタイプの他のオブジェクトと比較されていることを確認できない理由をもう少し説明していただけますか。上記のコードでsecond.getKey()は、と同じタイプのT1タイプを返します。first.getKey()

4

3 に答える 3

9

私は自分のクラスをそのように宣言します:

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> 

オブジェクトが同じタイプのオブジェクトと同等であることを意味します(エラーは、コンパイラがオブジェクトが同じタイプの他のオブジェクトと比較されていることを確認できないことを意味します)。


私が編集したコードは正しくコンパイルされます。

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> {
    private T1 key;
    private T2 value;

    public T1 getKey() {
        return key;
    }

    public T2 getValue() {
        return value;
    }

    public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            return first.getKey().compareTo(second.getKey());
        }
    };

    public static void test() {
        Pair<String, Integer> p1 = new Pair<String, Integer>();
        Pair<String, Integer> p2 = new Pair<String, Integer>();

        p1.KEY_COMPARATOR.compare(p1, p2);
    }
}

ただし、コンパレータの個別のクラス(または静的な最終クラス)を作成して、より直感的に使用できるようにし、各ペアインスタンスの重みを増やさないようにする必要があります。

于 2012-10-23T08:22:00.720 に答える
8

最初にインターフェース設計を見てみましょう。

public interface Comparable<T> { 

   public int compareTo(T o);

} 

それは私たちが言わなければならない非常に典型的です。したがって、クラスで実装する必要がある場合は、これを実行します。

pubilc class ICanComparteWithMyself implements Comparable<ICanComparteWithMyself> { 

public int compareTo(ICanComparteWithMyselfo)    
   //code for compration
} 

ジェネリックパラメーターのタイプを確認したら、何を操作するかを決定します。したがって、ジェネリックの場合も同じように動作します。

public class ICanCompareMyGeneric<T> implements Comparable<T> {

   public int compareTo(T o)    
       //code for compration
    } 
}

あなたの場合、ジェネリックパラメータの実装が独自のComparableであることを保証したいので、これを行う必要があります

public class MyGenericCanCompareToItself<T extends Comparable<T>> { 

}

ご覧のとおり、これは非常に一般的に使用されています。予想される(または予想されない)制限は、Comparableforitの自己型を実装するクラスで作業できることです。私たちが持っていた場合

 public class ICanCompareStrings implements Comparable<String> {
      public int compareTo(String o)    
           //code for compration
      }
 }

したがって、MyGenericCanCompareToItselfジェネリックパラメータとしてのクラスの場合、クラスは使用できますが、は使用できpublic MyGenericCanCompareToItselfませんICanCompareStrings

編集:

だから私たちが今基本をカバーしたとき、私たちはあなたの問題を解決するために行くことができます

クラスの説明は次のようになります

public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>>

これはあまり意味がないので、<?>

この説明によると:

私はPairクラスであり、2つのジェネリックパラメーターを使用して、知らないものとの比較を使用できます。

このコードを使用すると、一般的なパラメーターがそれを認識しない前に進行することはできず、そこで操作すると、次のような結果になります。

first.getKey.compareTo(null);

そして、これがキャストしようとしたときにコードがコンパイルされない理由であり、期待される型はnullです。


これを変更するには、ジェネリックパラメータが比較可能である必要があるタイプを限定する必要があります。

たとえば、それ自体で比較することができます

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>

この説明によると:

私は2つのパラメーターで動作するPairクラスであり、それぞれをそれ自体と比較できます。

そして、これはおそらくあなたが探しているものです、さらにそれらはT1またはT2のスーパークラスであることができる何かで比較することができます

public class Pair<T1 extends Comparable<? super T1>, T2 extends Comparable<? super T2>>

この説明によると:

私は2つのパラメーターで動作するペアクラスであり、それぞれがそれらから提供されるクラスと比較できます。

これがジェネリックスであなたを助けることを願っています;-)。

于 2012-10-23T08:37:27.273 に答える
-1

の違いを知っている場合:

List<Object>

List<String>

...それは簡単になります。基本的に、これらはJavaでは2つの異なるタイプです(あなたが思うように「同じ」リストタイプではありません)。

ジェネリック型の「ロジック」は、頭の中で考えているように、またはそうであるように見えるように、それほど単純ではありません。

「ペア」クラスは次のように宣言する必要があると思います。

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>

すでに「T1」と「T2」を比較可能にしているのに、なぜコンパレータを実装したいのでしょうか。

「Collections.sort(myCollection、myComparator)」を使用する場合は、「T1」と「T2」が「比較可能」であることを宣言する必要はありません...「KEY_COMPARATOR」がそれらを受け入れることを確認してください。 ..

いずれにせよ、コードには冗長性があります。

于 2012-10-23T09:06:20.240 に答える