2009-04-29 9 views
5

Con il tipo Integer si può fare questo:Java Generics e Infinity (comparabili)

int lowest = Integer.MIN_VALUE; 

Cosa posso fare se uso farmaci generici?

K lowest = <...>; 

Ho bisogno di questo, al fine di implementare qualcosa di simile ad un CodaConPriorita. 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 passaggio. L'unica cosa che posso fare è impostare la chiave del nodo sul minuto corrente. Non sono sicuro che sia abbastanza

+0

Sareste in grado di offrire alcuni esempi di codice che illustrano come si desidera utilizzare K? –

+0

Puoi approfondire un po '? Qualche codice rilevante sarebbe bello. –

+0

Per inciso, le versioni oggetto di valori letterali numerici si estendono tutti java.lang.Number. Sfortunatamente, Number non ha nulla come getMaximumValue(). – Powerlord

risposta

4

Questo non ha alcun senso ...

Dato che non si sa che cosa è K, a quel punto, (vale a dire Stai attuazione genericamente ... duh!) Non si può specificare un limite minimo/massimo per esso.

in un caso in cui K potrebbe essere un int, long, stringa o un oggetto, non si poteva ragionevolmente immaginare di utilizzare

Integer.MIN_VALUE, "" o NULL.

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

+2

Potrebbe trattarsi di qualcuno proveniente da uno sfondo C++, dove è banale usare solo numeric_limits :: max e numeric_limits :: min. Ciò ti consente di scrivere codice che gestisce caratteri, doppi, int, integer a 64 bit o anche classi numeriche personalizzate. – Eclipse

+0

Mi sono imbattuto in questo mentre cercavo la stessa idea ed ecco il mio caso d'uso: 1. Ho un'interfaccia con il seguente metodo 'Comparable getGroupIndex (String groupName)' questo metodo restituisce 'null' se' groupName' è sconosciuto. 2. In una classe in cui chiamo il metodo sopra, se il valore restituito è 'null', voglio metterlo alla fine di un elenco (trattarlo come se restituisse il valore max per i tipi comparabili). Ho intenzione di risolvere questo problema restituendo un valore massimo anziché null, ma solo voluto far luce su un caso d'uso. – mwakerman

1

Uh non dipende dal tipo di K?

Il punto di Generics è che K può essere qualsiasi tipo (o qualsiasi sottoclasse di un determinato tipo); per poter chiamare i metodi su K o accedere alle sue proprietà, è necessario limitare i limiti di tipo con i caratteri jolly.

+0

Bene, K è paragonabile. –

+1

Sembra una cosa valida da volere: se è un int, voglio il valore più basso, ma se è lungo, voglio il valore più basso. Non sono sicuro che ci sia una risposta semplice. Se non stavi usando Generics (passando solo un numero o un paragone), potresti probabilmente usare la riflessione per risolvere la maggior parte dei casi (i numeri generalmente hanno lo stesso campo .MIN_VALUE credo) –

+0

Paragonabile a cosa? È paragonabile alle altre K che non conoscerai. –

4

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

Pensa a una classe Time che implementa comparabili. Non c'è MAX_VALUE per Tempo anche se è paragonabile.

1

solo perché un oggetto è paragonabile non significa che deve avere un valore minimo. La ragione per cui ha un valore minimo di - (2^(31)) è perché hai bisogno di 1 bit per un segno, quindi 2^31 è il più grande (o il più piccolo) possibile numero intero che può essere memorizzato. Per cose come la stringa, non ha alcun senso poiché non esiste la stringa più grande/più piccola possibile, è legata alla memoria.

+0

C'è sicuramente una stringa più piccola possibile: "". È solo il più grande vincolato alla memoria, – Eclipse

+0

Le regole di ordinamento sono contestuali. Potrei facilmente definire un ordine che mette le stringhe vuote per ultime. – erickson

1

Potrebbe essere necessario creare un'interfaccia "IInfinity" e avere K estende IInfinity e IInfinity per avere un metodo "getInfinityValue()", quindi avvolgere/estendere un numero intero, doppio, BigDecimal, ecc. In una classe che implementa IInfinity ... e ugh!

1

Fondamentalmente si desidera che qualsiasi tipo di K esegua alcune funzioni statiche che indicano il minimo e il massimo che obbediscono alle proprietà matematiche standard.

Suppongo che per questo senso di minimo (o massimo) di utilizzo si desideri che qualsiasi oggetto Comparabile abbia questi metodi. (o campi statici). Se ti interessano solo i tuoi oggetti personalizzati, il modo per farlo sarebbe quello di ereditare tutto da un tipo di dati astratto che ha dichiarato campi statici per MINVALUE e MAX_VALUE e quindi il tuo tipo sarebbe varaibles.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)

4

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

ATTENZIONE: Questo codice è pericoloso. Per favore sii misericordioso con me per aver postato 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; 
     } 
    } 
} 
+0

Ok, questo è assolutamente strano. Abbiamo fatto lo stesso commento sulla domanda in un secondo l'uno dall'altro, e poi abbiamo aspettato 20 minuti e pubblicato quasi lo stesso codice entro 15 secondi l'uno dall'altro. Penso di dover fare una breve pausa ... –

+0

@mmyers: Weird! Penso che farò una lunga pausa, me stesso. :) –

+1

Non sono sicuro che sia peggio, però: il mio uso della riflessione per trovare un costruttore (per una classe potenzialmente non banale) o il cast di un non-K per K. –

1

non considerare la K un generico, ma utilizzando un'interfaccia che avvolge l'involucro primitivo (un doppio involucro!).

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

} 

Brevemente, l'idea è che ogni volta che una nuova classe viene istanziata, viene creato un valore minimo e messo in un hashmap statico che memorizza i valori minimi per ciascuna 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 paragonabile ad altri esempi di sé in generale.

Uno svantaggio è che quando si chiama getMinValue si avranno avvisi del compilatore, poiché il tipo di ritorno non avrà informazioni generiche. Potrebbe esserci un modo più elegante intorno a questo, ma non riesco a pensarci proprio ora.

Questa idea generale potrebbe essere piuttosto bella nel complesso. Tuttavia, dovrei davvero sottolineare: questo si interromperà assolutamente se lo proverai con qualsiasi polimorfismo o qualsiasi mix di classi comparabili tra loro. Long s e Integer s nello stesso albero ti distruggeranno completamente.

2

ehm ... qual è il problema?

PriorityQueue, come tutti gli Collections, consente di utilizzare un'istanza di un oggetto a remove dalla raccolta.

+0

Haha. Focus :-) – KarlP

+0

Ben detto. Raccomando che xhaker controlli il codice sorgente per la classe PriorityQueue per un esempio. –

2

È possibile creare una classe wrapper che "aggiunge" un valore minimo e massimo a tutti i tipi. Ha solo due istanze statiche che rappresentano il minimo e il massimo, quindi altre istanze racchiudono qualche altro valore di qualche 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); 
    } 
}