Javaジェネリックと無限(比較可能)
-
03-07-2019 - |
質問
整数型を使用すると、次のことができます。
int lowest = Integer.MIN_VALUE;
ジェネリックを使用する場合、どうすればよいですか?
K lowest = <...>;
PriorityQueueに似たものを実装するには、これが必要です。 キューから削除したいノードにアクセスできますが、それは最小ではありません。
1. I need to make it the min by decreasing the key of that node,
2. And then remove the min.
最初のステップにこだわっています。できることは、ノードのキーを現在の最小値に設定することだけです。十分かどうかわからない。
解決
これは意味がありません...
その時点でKが何であるかわからない場合(つまり、一般的に実装している場合...当たり前!)、最小/最大の境界を指定することはできません。
Kがint、long、string ORオブジェクトになる可能性がある場合、使用することを賢明に推測できませんでした
Integer.MIN_VALUE、&quot;&quot;またはNULL。
探しているのはK.MIN_VALUE_OF_EVENTUAL_TYPEでしょうが、存在しません。
他のヒント
すべての比較可能なタイプに、 MIN_VALUE
または MAX_VALUE
の一般的な形式はありません。
同等のものを実装する Time
クラスについて考えてください。比較可能であっても、時間の MAX_VALUE
はありません。
このような動作が必要になるシナリオを想像しようとしています。これは私が思いつく最高の方法です...
警告:このコードは危険です。そのような憎悪を投稿するために私に慈悲してください。これは概念実証にすぎません。
public class Lowest<K> implements Comparable<K> {
public int compareTo(K other) {
return -1;
}
}
そして...
public class Test {
public <K extends Comparable<K>> K findMaximum(List<K> values) throws Exception {
K lowest = (K) new Lowest<K>(); /// XXX DANGER! Losing compile-time safety!!!
K maximum = lowest;
for (K value : values) {
if (maximum.compareTo(value) < 0) {
maximum = value;
}
}
if (maximum == lowest) {
throw new Exception("Could not find a maximum value");
} else {
return maximum;
}
}
}
「追加」するラッパークラスを作成できます。すべてのタイプの最小値と最大値。最小値と最大値を表す2つの静的インスタンスがあり、他のインスタンスはあるタイプの他の値をラップします。比較を行うとき、物事の1つが最小または最大であるかどうかをチェックし、適切な結果を返します。それ以外の場合は、基になる型と同じ比較を行うだけです。このようなもの:
class Extended<T extends Comparable<? super T>> implements Comparable<Extended<T>> {
private Extended() { }
private static Extended min = new Extended();
private static Extended max = new Extended();
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Extended<T> getMin() {
return (Extended<T>)min;
}
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Extended<T> getMax() {
return (Extended<T>)max;
}
public T value;
public Extended(T x) { value = x; }
public int compareTo(Extended<T> other) {
if (this == other) return 0;
else if (this == min || other == max) return -1;
else if (this == max || other == min) return 1;
else return this.value.compareTo(other.value);
}
}
えー...また何が問題なの?
PriorityQueue (すべて< a href = "http://java.sun.com/javase/6/docs/api/java/util/Collection.html#remove(java.lang.Object)" rel = "nofollow noreferrer">コレクション、オブジェクトのインスタンスを使用してコレクションから削除します。
ええと、これはタイプKに依存しませんか?
Genericsのポイントは、Kは任意の型(または特定の型の任意のサブクラス)にできることです。 Kのメソッドを呼び出したり、Kのプロパティにアクセスしたりするには、ワイルドカードで型の境界を制限する必要があります。
オブジェクトが比較可能であるからといって、最小値が必要というわけではありません。 intの最小値が-(2 ^(31))である理由は、符号に1ビットが必要であり、2 ^ 31が格納可能な最大(または最小)整数であるためです。文字列のようなものについては、最大/最小の文字列が存在しないため、意味がありません。メモリバウンドです。
インターフェース「IInfinity」を作成し、KがIInfinityを拡張し、IInfinityがメソッド「getInfinityValue()」を使用して、クラスでInteger、Double、BigDecimalなどをラップ/拡張する必要がある場合がありますIInfinityを実装します...とうーん!
基本的に、タイプKにいくつかの静的関数を実装してほしいと思います。これは標準的な数学的性質に従う最低と最高を言います。
この最低(または最高)の感覚を使用するには、Comparableオブジェクトにこれらのメソッドが必要だと思います。 (または静的フィールド)。独自のカスタムオブジェクトのみに関心がある場合、これを行う方法は、すべてがMINVALUEおよびMAX_VALUEの静的フィールドを宣言した抽象データ型から継承し、型変数がになるようにすることです。他のクラスでこの機能が必要な場合は、異なるクラスのこれらのプロパティを追跡する何らかの外部ハッシュマップを作成する必要があります(ただし、かなりいものになります)
K
をジェネリックにするのではなく、プリミティブラッパー(ダブルラッパー!)をラップするインターフェイスを使用することを検討してください。
import java.util.HashMap;
public class NodeWrapper<K extends Comparable<K>> implements Comparable<NodeWrapper<K>> {
private static HashMap<Class, NodeWrapper> minVals = new HashMap<Class, NodeWrapper>();
private K value;
private NodeWrapper() {
super();
}
public NodeWrapper(K value, Class<K> clazz) {
super();
this.value = value;
if (minVals.get(clazz)==null) {
minVals.put(clazz, new NodeWrapper<K>());
}
}
public K getValue() {
return value;
}
public static NodeWrapper getMinValue(Class clazz){
return minVals.get(clazz);
}
public void setValue(K value) {
this.value = value;
}
@Override
public int compareTo(NodeWrapper<K> o) {
NodeWrapper min = minVals.get(this.getClass());
if (this==min && o==min) {
return 0;
} else if (this==min){
return -1;
} else if (o==min){
return 1;
} else {
return this.value.compareTo(o.value);
}
}
}
簡単に言うと、新しいクラスがインスタンス化されるたびに、最小値が作成され、各クラスの最小値を格納する静的ハッシュマップに入れられます。 (実際には、これらの値はまったく何でもない、単なる監視オブジェクトですが、オブジェクトの等価性を使用して最小値かどうかを判断するため、これはまったく問題ありません。)必要なのは、ラップされたオブジェクトが比較可能であることだけです一般にそれ自体の他のインスタンスに。
1つの欠点は、 getMinValue
を呼び出すと、戻り値の型に一般的な情報がないため、コンパイラの警告が表示されることです。これについてはもっとエレガントな方法があるかもしれませんが、今は考えられません。
この一般的な考え方は、全体的にかなりいいかもしれません。しかし、私は本当に強調する必要があります:多型または相互に比較可能なクラスの混合で試してみると、これは絶対に壊れます。同じツリー内の Long
sと Integer
sは完全にあなたを破壊します。