Domanda

Con il tipo Integer puoi farlo:

int lowest = Integer.MIN_VALUE;

Cosa posso fare se uso generici?

K lowest = <...>;

Ne ho bisogno per implementare qualcosa di simile a PriorityQueue. Ho accesso a un nodo che voglio rimuovere dalla coda, ma non è il minimo.

1. I need to make it the min by decreasing the key of that node,
2. And then remove the min.

Sono bloccato sul primo passo. L'unica cosa che posso fare è impostare la chiave del nodo sul minimo corrente. Non sono sicuro che sia abbastanza.

È stato utile?

Soluzione

Questo non ha alcun senso ...

Dato che non sai cosa sia K a quel punto, (cioè lo stai implementando genericamente ... duh!) non puoi specificare un limite min / max per esso.

in un caso in cui K potrebbe essere un oggetto int, long, stringa OR, che non si può indovinare sensibilmente da usare

Integer.MIN_VALUE, " " O NULL.

Suppongo che quello che stai cercando sia un K.MIN_VALUE_OF_EVENTUAL_TYPE ma che non esiste.

Altri suggerimenti

Non esiste una forma generica di MIN_VALUE o MAX_VALUE per tutti i tipi comparabili.

Pensa a una classe Time che implementa comparabile. Non esiste MAX_VALUE per Time anche se è comparabile.

Sto cercando di immaginare quale scenario richiederebbe un simile comportamento. Questo è il meglio che posso inventare ...

ATTENZIONE: questo codice è pericoloso. Ti prego, abbi pietà di me per aver pubblicato un simile abominio. È solo una prova di concetto.

public class Lowest<K> implements Comparable<K> {
    public int compareTo(K other) {
        return -1;
    }
}

E poi ...

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;
        }
    }
}

Puoi creare una classe wrapper che " aggiunge " un valore minimo e massimo per tutti i tipi. Ha solo due istanze statiche che rappresentano il minimo e il massimo, quindi altre istanze racchiudono un altro valore di un certo tipo. Quando facciamo un confronto, controlliamo se una delle cose è il minimo o il massimo e restituiamo il risultato corretto; e altrimenti facciamo lo stesso confronto del tipo sottostante. Qualcosa del genere:

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);
    }
}

ehm ... qual è il problema di nuovo?

PriorityQueue , come tutti < a href = "http://java.sun.com/javase/6/docs/api/java/util/Collection.html#remove(java.lang.Object)" rel = "nofollow noreferrer"> Collezioni , consente di utilizzare un'istanza di un oggetto per rimuovilo dalla raccolta.

Uh non dipende da che tipo K è?

Il punto di Generics è che K può essere qualsiasi tipo (o qualsiasi sottoclasse di un certo tipo); per poter chiamare metodi su K o accedervi, devi limitarne i limiti con i caratteri jolly.

solo perché un oggetto è comparabile non significa che debba avere un valore minimo. Il motivo int ha un valore minimo di - (2 ^ (31)) perché è necessario 1 bit per un segno, quindi 2 ^ 31 è il numero intero più grande (o più piccolo) possibile che può essere memorizzato. Per cose come la stringa, non ha alcun senso poiché non esiste una stringa più grande / più piccola possibile, è legata alla memoria.

Potrebbe essere necessario creare un'interfaccia "IInfinity", e avere K estende IInfinity e IInfinity per avere un metodo "getInfinityValue () " ;, quindi avvolgere / estendere Integer, Double, BigDecimal, ecc. in una classe che implementa la verità ... e ugh!

Fondamentalmente si desidera che qualsiasi tipo K implementi alcune funzioni statiche dire il più basso e il più alto che obbediscono alle proprietà matematiche standard.

Suppongo che affinché questo senso del più basso (o il più alto) sia utilizzabile, si vorrebbe che qualsiasi oggetto comparabile avesse questi metodi. (o campi statici). Se sei interessato solo ai tuoi oggetti personalizzati, il modo per farlo sarebbe quello di avere tutto ciò che eredita da un tipo di dati astratto che ha dichiarato campi statici per MINVALUE e MAX_VALUE e quindi il tuo tipo sarebbe variabile. Se hai bisogno di questa funzionalità per altre classi, dovrai creare una sorta di hashmap esterna che tenga traccia di queste proprietà per classi diverse (ma sarebbe piuttosto brutto)

Considera di non rendere K un generico, ma di utilizzare un'interfaccia che avvolga il wrapper primitivo (un doppio wrapper!).

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);
        }
    }

}

In breve, l'idea è che ogni volta che viene istanziata una nuova classe, viene creato un valore minimo e inserito in una hashmap statica che memorizza i valori minimi per ogni classe. (In realtà, questi valori non sono NIENTE, solo un oggetto sentinella, ma poiché useremo l'uguaglianza degli oggetti per determinare se qualcosa è il valore minimo, questo non è affatto un problema.) Tutto ciò che è necessario è che l'oggetto avvolto sia comparabile ad altri casi di se stesso in generale.

Uno svantaggio è che quando si chiama getMinValue si avranno avvisi del compilatore, poiché il tipo restituito non avrà informazioni generiche. Potrebbe esserci un modo più elegante per aggirare questo, ma non riesco a pensarci adesso.

Questa idea generale potrebbe essere piuttosto carina nel complesso. Tuttavia, dovrei davvero sottolineare: questo si romperà assolutamente se lo provi con qualsiasi polimorfismo o mescolando classi reciprocamente comparabili. Long se Integer nello stesso albero ti distruggeranno completamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top