Pregunta

Estoy tratando de anular el método igual a para una clase parametrizada.

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Tuple))
        return false;

    Tuple<E> other = (Tuple<E>) obj; //unchecked cast
    if (!a0.equals(other.a0) && !a0.equals(other.a1)) {
        return false;
    }
    if (!a1.equals(other.a1) && !a1.equals(other.a0)) {
        return false;
    }

    return true;
}

¿Cómo puedo asegurarme de que < E > del objeto other es el mismo que this ?

¿Fue útil?

Solución

Puede hacerlo reteniendo una referencia al tipo Class < E > . Sin embargo, en mi opinión, las pruebas de igualdad deberían ser sobre los valores que representan los objetos en lugar de los tipos concretos que los valores expresan .

Un ejemplo clásico de esto es la API de Colecciones, por ejemplo. new ArrayList < String > (). equals (new LinkedList < Object > ()) devuelve true . Si bien estos tienen tipos completamente diferentes, representan el mismo valor, es decir, "una colección vacía".

Personalmente, si dos Tuple s representan los mismos datos (por ejemplo, (" a " ;, " b ") ) no son iguales, porque uno es de escriba Tuple < String > mientras que el otro es Tuple < Object > ?

Otros consejos

Debido al borrado no puedes. Lo mejor que puede hacer es almacenar en la clase tupla el tipo que planea que la Tuple contenga en una "clase java.lang.lang". miembro de campo. Luego, podría comparar esos campos para asegurarse de que la clase tupla contenga los mismos tipos.

También vea este hilo: ¿Cuál es el equivalente del par C ++ < L , R > en Java?

Sería útil si publicas más sobre tu clase. Creo que el reparto no verificado y la cantidad de campos que equiparas significa que debería ser Tupla < E, F > no?

EDITAR: aquí hay una clase útil de Par que uso regularmente (puede adaptar su clase Tuple si es necesario). Tenga en cuenta que, de manera similar a las sugerencias de otros, esta clase simplemente permite que los miembros contenidos decidan la cuestión de la igualdad. Su caso de uso es lo que debería determinar si la igualdad se basa realmente en el tipo de miembros contenidos.

/**
 * Adapted from http://forums.sun.com/thread.jspa?threadID=5132045
 * 
 * 
 * @author Tim Harsch
 *
 * @param <L>
 * @param <R>
 */
public class Pair<L, R> {

    private final L left;
    private final R right;

    public R getRight() {
        return right;
    } // end getter

    public L getLeft() {
        return left;
    } // end getter

    public Pair(final L left, final R right) {
        this.left = left;
        this.right = right;
    } // end constructor

    public static <A, B> Pair<A, B> create(A left, B right) {
        return new Pair<A, B>(left, right);
    } // end factory method

    @Override
    public final boolean equals(Object o) {
        if (!(o instanceof Pair<?,?>))
            return false;

        final Pair<?, ?> other = (Pair<?, ?>) o;
        return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight());
    } // end method

    public static final boolean equal(Object o1, Object o2) {
        if (o1 == null) {
            return o2 == null;
        }
        return o1.equals(o2);
    } // end method

    @Override
    public int hashCode() {
        int hLeft = getLeft() == null ? 0 : getLeft().hashCode();
        int hRight = getRight() == null ? 0 : getRight().hashCode();

        return hLeft + (37 * hRight);
    } // end method

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('<');
        if( left == null ) {
            sb.append("null");
        } else {
            sb.append(left.toString());
        } // end if
        sb.append(',');
        if( right == null ) {
            sb.append("null");
        } else {
            sb.append(right.toString());
        } // end if
        sb.append('>');
        return sb.toString();
    } // end method
} // end class

Me encontré con este problema yo mismo, y en mi caso particular, no necesitaba saber el tipo E.

Por ejemplo:

public class Example<E> {
    E value;

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Example<?> other = (Example<?>) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }
}

En el código anterior, no hay conversión sin marcar debido al uso de Ejemplo <? > . El parámetro de tipo comodín '?' salva el día.

Lamentablemente, no puedes hacer esto en tiempo de compilación; La información se ha ido. Tales son las consecuencias de borrado de tipo . Una alternativa es almacenar el parámetro como una instancia de Class y luego buscarlo más tarde.

Dado que los genéricos se borran en tiempo de compilación , usted Básicamente no puedo. En el tiempo de ejecución, cualquier parámetro de tipo desaparece y, en lo que respecta a la JVM, son exactamente iguales en todos los aspectos.

La forma de evitarlo es almacenar un campo Class que represente el tipo y crear el objeto con ese tipo en el constructor.

Un constructor de muestra:

public class Tuple < E > {

    public Tuple(Class<E> c) {
        //store the class
    }

}

O podrías usar una fábrica:

public static <E> Tuple <E> getTuple(Class<E> type) {
    // Create and return the tuple, 
    // just store that type variable in it 
    // for future use in equals.
}

Las sugerencias para retener una referencia al tipo de E con un objeto Class parecen ineficientes (son muchas referencias inútiles a un Class ocupando memoria) y no tiene sentido para su problema.

No es generalmente cierto que Foo < Bar > y Foo < Baz > deberían ser desiguales. Por lo tanto, no necesita E . Y, en el código que escribió, ni siquiera lo necesita para compilar. Simplemente envíe a Tuple <? & Gt; , ya que eso es todo lo que sabe sobre Tuple en ese momento. Todavía se compila y todo.

Si se le pasan Tuple s con datos de dos tipos completamente diferentes, esos elementos no serán iguales , y su método devolverá false , según lo deseado. (Uno espera - depende de esos tipos que implementan igual a con sensatez).

Fuera de tema: ¿se da cuenta de que según su implementación, Tuple (a0, a1) es igual a Tuple (a1, a1)? Sospecho que eso no es lo que quieres ...

Sobre el tema, como han dicho otros, la eliminación hace que esto sea imposible. Pero debe reconsiderar por qué quiere esto: la verificación de igualdad solo ocurre en tiempo de ejecución, y los genéricos son solo en tiempo de compilación . Conceptualmente, una variable tiene parámetros genéricos, pero un objeto no. Por lo tanto, cuando se compara la igualdad de objetos, los parámetros genéricos no importan en absoluto; de todos modos, no puede tomar ninguna acción apropiada basada en ellos en tiempo de ejecución.

La igualdad de objetos y la covarianza / contravarianza de parámetros genéricos son dos preocupaciones ortogonales.

Estoy de acuerdo con los comentarios anteriores, ¿por qué la clase E debe ser igual? y ¿cómo quieres tratar las subclases de E?

De todos modos, dado que aquí hay una muestra de código que puede ayudarlo:

public class Example<T> {

  T t;

  public Example(T t) {
    this.t = t;
  }

  public static void main(String[] args) {
    final String s = "string";
    final Integer i = 1;
    final Number n = 1;

    final Example<String> exampleString = new Example<String>(s);
    final Example<Integer> exampleInteger = new Example<Integer>(i);
    final Example<Number> exampleNumber = new Example<Number>(n);

    System.out.println("exampleString subclass "  + exampleString.t.getClass());
    System.out.println("exmapleIntger subclass " + exampleInteger.t.getClass());
    System.out.println("exmapleNumber subclass " + exampleNumber.t.getClass());
    System.out.println("Integer equals Number = " + 
        exampleInteger.t.equals(exampleNumber.t));
  }
}

Puede llamar a t.getClass () para obtener información de clase sobre el tipo de T (suponiendo que no sea nulo, por supuesto).

Espero que esto ayude.

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