2011-02-16 22 views
14

Tengo una clase genérica con dos variables de tipo, que implementa java.lang.Comparable.Crear un compareTo a una clase genérica que implementa Comparable

 
public class DoubleKey<K,J> implements Comparable<DoubleKey<K,J>>{ 

    private K key1; 
    private J key2; 

    public DoubleKey(K key1, J key2){ 
     this.key1 = key1; 
     this.key2 = key2; 
    } 

    public K getFirstKey(){ 
     return this.key1; 
    } 

    public J getSecondKey(){ 
     return this.key2; 
    } 

    // need for Comparable interface 
    public int compareTo(DoubleKey<K,J> aThat){ 
     ... 
    } 

} 

Porque lo implementé con Comparable, tengo que escribir el método compareTo(). Como K, J puede ser CUALQUIER tipo, tengo problemas para compararlos por completo. ¿Hay alguna manera de poder atrapar todos los tipos posibles (primitivo, envoltorio, objeto) en la comparación? ¡Gracias por la ayuda!

Respuesta

9

Entonces, para resumir la mencionada arriba y que hay que aclarar juntos en un código de trabajo esto es:

public class DoubleKey<K extends Comparable<K>, J extends Comparable<J>> 
     implements Comparable<DoubleKey<K, J>> { 

    private K key1; 
    private J key2; 

    public DoubleKey(K key1, J key2) { 
     this.key1 = key1; 
     this.key2 = key2; 
    } 

    public K getFirstKey() { 
     return this.key1; 
    } 

    public J getSecondKey() { 
     return this.key2; 
    } 

    public int compareTo(DoubleKey<K, J> that) { 

     int cmp = this.getFirstKey().compareTo(that.getFirstKey()); 
     if (cmp == 0) 
      cmp = this.getSecondKey().compareTo(that.getSecondKey()); 
     return cmp; 
    } 
} 
0

Tendrá que definir una regla cuando a DoubleKey<K,J> es más pequeño, más grande o igual a este. Eso es lo que compara hacer. Tal vez, esa es mi conjetura real, no tiene mucho sentido comparar con instancias de DoubleKey<K,J>.

Si no guarda efectiva cómo se ordenan y sólo tendrá que aplicar cualquier pedido, intente esto:

public int compareTo(DoubleKey<K,J> that){ 
    // real codes needs checks for null values! 
    return (this.key1.toString() + this.key2.toString()).compareTo(that.key1.toString() + that.key2.toString()); 
} 
+0

Pero luego debe asegurarse de documentar esto (que 'compareTo' depende de' toString() 'de las partes), y que' compareTo' no es consistente con 'equals'. –

+0

Tiene sentido si usa, por ejemplo, DoubleKey .A continuación, puede usar compare para comparar los valores de objeto J cómo desea dependiendo de qué campos están en ellos llamando a sus propios métodos de comparación. Por ejemplo, tamaño y peso. Alternativamente, podría comparar las cadenas de teclas alfabéticamente. Todo depende del desarrollador del tipo de datos abstractos DoubleKey para implementar el comportamiento de su elección y documentarlo bien. –

0

primera manera: hashcodes uso, como

public int compareTo(DoubleKey<K,J> aThat){ 
    getFirstKey().hashCode() + getSecondKey().hashCode() - aThat.getFirstKey().hashCode() + aThat.getSecondKey().hashCode(); 
} 

(que debería pensar más en la fórmula)

Segunda forma: anuncio d comparador de constructor

public DoubleKey(K key1, J key2, Comparator cmp){ 
+1

La primera forma es incorrecta, porque "_ [No es necesario que si dos objetos son desiguales de acuerdo con el método igual (java.lang.Object), al llamar al método hashCode en cada uno de los dos objetos debe producir resultados enteros distintos. ] (http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode()) _ ", también el' int' en hashCode es arbitrario, no se puede asumir que un 'Objeto' con hachCode 42 es mayor que un' Object' con hashCode 1. –

+0

@Electro, por supuesto que está mal. Pero, no hay ningún criterio para comparar Objeto, por lo que puede usar Ordenar por hashCodes) –

3
 
public class DoubleKey< 
     K implements Comparable<K>, 
     J implements Comparable<J>> 
    implements Comparable<DoubleKey<K,J>> { 

    public int compareTo(DoubleKey<K,J> that){ 
     int cmp = this.key1.compareTo(that.key1); 
     if(cmp==0) cmp = this.key2.compareTo(that.key2); 
     return cmp; 
    } 
} 
+3

¿No es 'K se extiende Comparable ' en lugar de 'implementos'? –

+0

@Arne sí, eso es correcto. Las variables genéricas solo pueden ** extender **, no pueden ** implementar **, incluso si se trata de una interfaz. – Jairo

+0

* Porque K, J puede ser de ** CUALQUIER ** tipo * - ¿no era eso una condición previa? –

7

¿Le gustaría introducir un requisito de que K y J tienen un orden natural que se puede utilizar? En este caso se puede declarar una clase DoubleKey así:

class DoubleKey<K extends Comparable<K>, J extends Comparable<J>> 

continuación, se puede definir de compareTo como quiera que su DoubleKey. Puede hacer cosas como:

getFirstKey().compareTo(aThat.getFirstKey()) 

No se puede comparar cualquier instancia de K a una instancia de J, sin embargo. No hay orden definido sobre esos tipos.

Si estos tipos no tienen necesariamente un orden natural (muchos no lo hacen), se puede tomar una Comparator<K> y Comparator<J> como parámetros al constructor de la DoubleKey. Una clase que ya hace esto y que puede usar como ejemplo es la excelente clase Maps de Google Guava (consulte específicamente los métodos newTreeMap y los límites de los tipos que aceptan).

+0

lo que ** getFirstKey(). CompareTo (aThat.getFirstKey()) ** devuelve cuando 2 variables son iguales, y si no son iguales ? – Jairo

+1

Este es solo el contrato estándar 'Comparable'. En 'a.compareTo (b)', si son iguales 'compareTo' devuelve 0, si a b devuelve un número positivo (generalmente 1). – sjr

+2

'K extends Comparable ' sería mejor, ya que trata con subclases de clases Comparables de forma apropiada – newacct

0

Como suele ser el caso, existe una biblioteca que puede resolver su problema: Apache Commons lang3. A menudo uso las instancias Pair<L,R> como claves. Implementan Comparable.

Cuestiones relacionadas