Pregunta

Con el tipo Integer puedes hacer esto:

int lowest = Integer.MIN_VALUE;

¿Qué puedo hacer si uso genéricos?

K lowest = <...>;

Necesito esto para implementar algo similar a un PriorityQueue. Tengo acceso a un nodo que quiero eliminar de la cola, pero no es el mínimo.

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

Estoy atascado en el primer paso. Lo único que puedo hacer es configurar la clave del nodo al mínimo actual. No estoy seguro de que sea suficiente.

¿Fue útil?

Solución

Esto no tiene ningún sentido ...

Dado que no sabe qué es K en ese momento (es decir, lo está implementando de forma genérica ... ¡duh!), no puede especificar un límite mínimo / máximo para él.

en un caso en el que K podría ser un objeto int, long, string O, no se puede suponer que se pueda utilizar

Integer.MIN_VALUE, " " O NULL.

Supongo que lo que estás buscando es un K.MIN_VALUE_OF_EVENTUAL_TYPE pero eso no existe.

Otros consejos

No hay una forma genérica de MIN_VALUE o MAX_VALUE para todos los tipos comparables.

Piense en una clase de Time que implemente comparable. No hay MAX_VALUE para Time aunque sea comparable.

Estoy tratando de imaginar qué escenario requeriría tal comportamiento. Esto es lo mejor que se me ocurre ...

ADVERTENCIA: Este código es peligroso. Por favor, ten piedad de mí por publicar tal abominación. Es solo una prueba de concepto.

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

Y luego ...

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

Puede crear una clase contenedora que " agregue " Un valor mínimo y máximo para todos los tipos. Solo tiene dos instancias estáticas que representan el mínimo y el máximo, y luego otras instancias envuelven algún otro valor de algún tipo. Cuando hacemos una comparación, verificamos si una de las cosas es el mínimo o el máximo, y devolvemos el resultado adecuado; y de lo contrario, simplemente hacemos la misma comparación que el tipo subyacente. Algo como esto:

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

er ... ¿cuál es el problema otra vez?

PriorityQue , como todos < a href = "http://java.sun.com/javase/6/docs/api/java/util/Collection.html#remove(java.lang.Object)" rel = "nofollow noreferrer"> Colecciones , le permite usar una instancia de un objeto para eliminarlo de la colección.

Uh, ¿esto no depende del tipo K?

El punto de los genéricos es que K puede ser de cualquier tipo (o cualquier subclase de un tipo determinado); para poder llamar a métodos en K o acceder a sus propiedades, debe restringir los límites de los tipos con comodines.

solo porque un objeto sea comparable no significa que tenga que tener un valor mínimo. La razón por la que int tiene un valor mínimo de - (2 ^ (31)) es porque necesita 1 bit para un signo, por lo que 2 ^ 31 es el mayor entero (o el más pequeño) posible que se puede almacenar. Para cosas como la cadena, no tiene ningún sentido ya que no hay una cadena más grande / pequeña posible, está vinculada a la memoria.

Es posible que tengas que crear una interfaz "IInfinity", y tener K extiende IInfinity, e IInfinity para tener un método "getInfinityValue ()" y luego envolver / extender Integer, Double, BigDecimal, etc. en una clase eso implementa IInfinity ... y ugh!

Básicamente, usted quiere que cualquier tipo K implemente algunas funciones estáticas, como la más baja y la más alta, que obedecen las propiedades matemáticas estándar.

Supongo que para que este sentido de más bajo (o más alto) sea utilizable, desearía que cualquier objeto comparable tenga estos métodos. (o campos estáticos). Si solo está interesado en sus propios objetos personalizados, la forma de hacerlo sería tener todo lo heredado de un tipo de datos abstracto que declarara campos estáticos para MINVALUE y MAX_VALUE y luego su tipo de variables sería. Si necesitas esta funcionalidad para otras clases, deberás crear algún tipo de mapa de hash externo que rastree estas propiedades para diferentes clases (pero eso sería bastante feo)

Considere no hacer de K un genérico, sino usar una interfaz que envuelva el envoltorio primitivo (¡un envoltorio doble!).

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, la idea es que cada vez que se crea una instancia de una nueva clase, se crea un valor mínimo y se coloca en un mapa hash estático que almacena los valores mínimos para cada clase. (De hecho, estos valores son NADA en absoluto, solo un objeto centinela, pero como usaremos la igualdad de objetos para determinar si algo es el valor mínimo, esto no es ningún problema). Todo lo que es necesario es que el objeto envuelto sea comparable a otras instancias de sí mismo en general.

Un inconveniente es que cuando llama a getMinValue tendrá advertencias del compilador, ya que el tipo de retorno no tendrá información genérica. Puede haber una forma más elegante de evitar esto, pero no puedo pensar en ello ahora mismo.

Esta idea general puede ser bastante agradable en general. Sin embargo, realmente debo enfatizar: esto se romperá absolutamente si lo intentas con cualquier polimorfismo o cualquier mezcla de clases mutuamente comparables. Long sy Integer s en el mismo árbol te destruirán por completo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top