2011-06-23 7 views
14

Estoy tratando de escribir una función máxima genérica que requiere dos Comparable s.¿Cómo implementar una función genérica `max (comparable a, comparable b)` en Java?

Hasta ahora he

public static <T extends Comparable<?>> T max(T a, T b) { 
    if (a == null) { 
     if (b == null) return a; 
     else return b; 
    } 
    if (b == null) 
     return a; 
    return a.compareTo(b) > 0 ? a : b; 
} 

Esto no compila con

The method compareTo(capture#5-of ?) in the type Comparable<capture#5-of ?> is not applicable for the arguments (T) 

Lo que creo que esto dice es que que el ? en Comparable<?> puede ser interpretado como un tipo de parámetro a, y otro para el parámetro b, por lo que no se pueden comparar.

¿Cómo salgo de este agujero?

+0

En el bloque 'if (a == null)', no hay necesidad de la cláusula if anidada. Reducir el bloque a 'return b;' produce el mismo resultado ('null' cuando' b' es 'null',' b' en caso contrario). – benjamin

+0

Ver [org.apache.commons.lang3.ObjectUtils.compare] (https://commons.apache.org/proper/commons-lang/javadocs/api-3.6/org/apache/commons/lang3/ObjectUtils.html# compare-TT-) –

Respuesta

24

Para obtener mejores resultados, debe usar public static <T extends Comparable<? super T>> T max(T a, T b).

El problema con <T extends Comparable<?>> es que esto indica que el tipo T es comparable a algún tipo, pero no se sabe qué es ese tipo. Por supuesto, el sentido común dictaría que una clase que implementa Comparable debería ser capaz de ser comparable al menos a sí misma (es decir, ser capaz de comparar con objetos de su propio tipo), pero técnicamente no hay nada que impida que la clase A implemente Comparable<B>, donde A y B no tienen nada que ver el uno con el otro. <T extends Comparable<T>> resuelve este problema.

Pero hay un problema sutil con eso. Supongamos que la clase X implementa Comparable<X>, y tengo una clase Y que se extiende X. Por lo tanto, la clase Y implementa automáticamente Comparable<X> por herencia. La clase Y tampoco puede implementar Comparable<Y> porque una clase no puede implementar una interfaz dos veces con diferentes parámetros de tipo. Esto no es realmente un problema, ya que las instancias de Y son instancias de X, entonces Y es comparable a todas las instancias de Y. Pero el problema es que no puede usar el tipo Y con su función <T extends Comparable<T>> T max(T a, T b), porque Y no implementa Comparable<Y>. Los límites son muy estrictos.<T extends Comparable<? super T>> soluciona el problema, porque es suficiente para que T sea comparable a algún supertipo de T (que incluiría todas las instancias T). Recordar la regla PECS - productor extends, consumidor super - en este caso, Comparable es un consumidor (toma en un objeto para comparar), por lo que super tiene sentido.

Este es el tipo de límites utilizados por todas las funciones de ordenamiento y clasificación en la biblioteca de Java.

4

Obtiene este error porque Comparable<?> básicamente dice que es comparable a algo sin ningún detalle. Debería escribir Comparable<T> para que el compilador sepa que el tipo T es comparable a sí mismo.

+0

Gracias - ahora para resolver el problema real, que era portarlo a Scala! –

1

Respondiendo a mi propia pregunta de los enlaces relacionados generados de SO - esto parece ser un duplicado sutil de Fun with Java generics, ¡aunque supongo que no me puede culpar por no encontrarlo dado el título!

La solución más simple parece ser

public static <T extends Comparable<T>> T max(T a, T b) { 
    if (a == null) { 
     if (b == null) return a; 
     else return b; 
    } 
    if (b == null) 
     return a; 
    return a.compareTo(b) > 0 ? a : b; 
} 
1

He escrito una clase de utilidad para esto. Tal vez le sea útil (la biblioteca es Open Source):

http://softsmithy.sourceforge.net/lib/docs/api/org/softsmithy/lib/util/Comparables.html

Inicio:

http://www.softsmithy.org

Descargar:

http://sourceforge.net/projects/softsmithy/files/softsmithy/

Maven:

<dependency> 
    <groupid>org.softsmithy.lib</groupid> 
    <artifactid>lib-core</artifactid> 
    <version>0.1</version> 
</dependency> 
+0

Genial, gracias. Este es el tipo de cosas que no me gustan y que no forman parte de la biblioteca estándar, dado el código que se necesita y lo fácil que es equivocarse. –

+0

Nota: Acabo de comprobar el código fuente: actualmente no admite valores nulos: http://softsmithy.hg.sourceforge.net/hgweb/softsmithy/lib/main-golden/file/5c4db802573b/lib-core/src /main/java/org/softsmithy/lib/util/Comparables.java – Puce

+0

:-) Gracias por venir limpio - Estoy seguro de que el mío no lo hubiera tenido. No he estado tratando con un dominio donde muchas fechas podrían no haber sido suministrado. –

Cuestiones relacionadas