Java Abstract Class Implementando una interfaz con Genéricos


Estoy tratando de definir una clase abstracta implementando Comparable. Cuando defino la clase con la siguiente definición:

public abstract class MyClass implements Comparable <MyClass>

Las subclases tienen que implementar compareTo(MyClass object). En su lugar, quiero que cada subclase implemente compareTo(SubClass object), aceptando un objeto de su propio tipo. Cuando intento definir la clase abstracta con algo como:

public abstract class MyClass implements Comparable <? extends MyClass>

Se queja de que "Un supertipo no puede especificar ningún comodín."

¿hay una solución?

Author: Cem, 2010-08-29

7 answers

Es un poco demasiado detallado en mi opinión, pero funciona:

public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {

}

public class SubClass extends MyClass<SubClass> {

    @Override
    public int compareTo(SubClass o) {
        // TODO Auto-generated method stub
        return 0;
    }

}
 41
Author: whiskeysierra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-05 08:44:47

Aparte de las dificultades mecánicas que estás encontrando para declarar las firmas, el objetivo no tiene mucho sentido. Usted está tratando de establecer una función de comparación covariante, que rompe toda la idea de establecer una interfaz que las clases derivadas pueden adaptar.

Si define alguna subclase SubClass de manera que sus instancias solo puedan compararse con otras instancias SubClass, entonces ¿cómo cumple SubClass el contrato definido por MyClass? Recordemos que MyClass está diciendo que ella y cualquier los tipos derivados se pueden comparar con otras instancias MyClass. Estás tratando de hacer que eso no sea cierto para SubClass, lo que significa que SubClass no satisface el contrato de MyClass: No puedes sustituir SubClass por MyClass, porque los requisitos de SubClass son más estrictos.

Este problema se centra en la covarianza y la contravarianza, y cómo permiten que las firmas de función cambien a través de la derivación de tipos. Puede relajar un requisito en el tipo de un argumento-aceptar un tipo más amplio que el la firma del supertipo exige-y puede fortalecer un requisito en un tipo de retorno-prometiendo devolver un tipo más estrecho que la firma del supertipo. Cada una de estas libertades todavía permite la sustitución perfecta del tipo derivado para el supertipo; un llamador no puede decir la diferencia cuando se utiliza el tipo derivado a través de la interfaz del supertipo, pero un llamador que utiliza el tipo derivado concretamente puede tomar ventaja de estas libertades.

La respuesta de Willi enseña algo sobre declaraciones genéricas, pero le insto a reconsiderar su objetivo antes de aceptar la técnica a expensas de la semántica.

 17
Author: seh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:22

Ver el propio ejemplo de Java:

public abstract class Enum<E extends Enum<E>> implements Comparable<E>
    public final int compareTo(E o)

Sobre el comentario de seh: usualmente el argumento es correcto. pero los genéricos hacen que las relaciones tipo sean más complicadas. una SubClase puede no ser un subtipo de MyClass en la solución de Willi....

SubClassA es un subtipo de MyClass<SubClassA>, pero no un subtipo de MyClass<SubClassB>

Type MyClass<X> define un contrato para compareTo(X) que todos sus subtipos deben cumplir. no hay ningún problema.

 3
Author: irreputable,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-30 09:24:27

No estoy seguro de que necesites la captura:

Primero, agregue el compareTo a la clase abstracta...

public abstract class MyClass implements Comparable <MyClass> {

@Override
public int compareTo(MyClass c) {
...
}    
}

Luego agregue las implementaciones...

public class MyClass1 extends MyClass {
...
}

public class MyClass2 extends MyClass {
...
}

Llamando a comparar llamará al método super type...

MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();

c1.compareTo(c2);
 1
Author: zevra0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-29 00:05:12
public abstract class MyClass<T> implements Comparable<T> {

}

public class SubClass extends MyClass<SubClass> {

    @Override
    public int compareTo(SubClass o) {
        // TODO Auto-generated method stub
        return 0;
    }

}
 1
Author: newacct,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-30 10:43:23

Encontró otra solución:

  1. Definir una interfaz en los campos que componen el comaprable (por ejemplo ComparableFoo)
  2. Implementar la interfaz en la clase padre
  3. Implementar Comparable en la clase padre.
  4. Escriba su implementación.

La solución debería tener este aspecto:

public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
    public int compareTo(ComparableFoo o) {
    // your implementation
    }
}

Esta solución implica que más cosas podrían implementar ComparableFoo-este no es probablemente el caso, pero luego está codificando a una interfaz y los genéricos la expresión es simple.

 1
Author: David Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-28 02:01:42

Sé que dijiste que querías "compareTo (objeto SubClase), aceptar un objeto de su propio tipo", pero aún así sugiero declarar la clase abstracta de esta manera:

public abstract class MyClass implements Comparable <Object>

Y haga una comprobación instanceof cuando anule compareTo en MySubClass:

@Override
public int compareTo(Object o) {
    if (o instanceof MySubClass)) {
        ...
    }
    else throw new IllegalArgumentException(...)
}

Similar a' igual 'o'clon'

 0
Author: Caroline Even,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-03 01:59:06