Pergunta

Eu estou tentando método equals substituição para uma classe 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;
}

Como posso ter certeza de que <E> do objeto other é o mesmo que this?

Foi útil?

Solução

Você pode fazê-lo através da retenção de uma referência ao tipo Class<E>. No entanto, na minha opinião, testes de igualdade deve ser sobre os valores dos objetos representam, em vez dos tipos de concreto os valores se expressas .

Um exemplo clássico disso é a API Collections, por exemplo. new ArrayList<String>().equals(new LinkedList<Object>()) retornos true. Enquanto estes têm tipos completamente diferentes, eles representam o mesmo valor, ou seja, "uma coleção vazia".

pessoalmente, deve dois Tuples que representam os mesmos dados (por exemplo ("a", "b")) não ser igual, porque uma é do tipo Tuple<String> enquanto o outro é Tuple<Object>?

Outras dicas

Por causa de apagamento você não pode. Sobre o melhor que poderia fazer é loja na classe tupla do tipo que você planeja para o Tuple de espera em um "java.lang.Class" membro de campo. Em seguida, você pode comparar esses campos para garantir que a classe tupla está segurando os mesmos tipos.

Veja também este tópico: O que é o equivalente da Par C ++ em Java?

Seria bom se você postar mais sobre a sua classe. Estou pensando o elenco desmarcada e seu número de campos que você equiparar significa que deve ser Tuple não?

EDIT: aqui é uma classe Par útil que eu uso regularmente (você pode adaptar sua classe Tuple se necessário). Note, semelhante a sugestões por outros desta classe apenas permite que os membros contidos decidir a questão da igualdade. Seu caso de uso é o que deve determinar se a igualdade é realmente baseado no tipo dos membros contidos.

/**
 * 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

Eu apenas corri para este problema sozinho, e no meu caso -particular-, eu não preciso saber o tipo E.

Por exemplo:

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

No código acima, não há nenhuma conversão desmarcada por causa de usar Example<?>. O parâmetro de tipo wildcard '?' salva o dia.

Infelizmente, você não pode fazer isso em tempo de compilação; a informação é ido. Tais são as consequências de Tipo de apagamento . Uma alternativa é armazenar o parâmetro como uma instância Class, e depois procurá-lo mais tarde.

Desde genéricos são apagados em tempo de compilação , você basicamente, não pode. Em tempo de execução, qualquer tipo de parâmetro está desaparecido, e, tanto quanto a JVM está em causa, eles são exatamente os mesmos em todos os aspectos.

A maneira de contornar isso é para armazenar um campo Class que representa o tipo, e criar o objeto com esse tipo no construtor.

Um construtor de exemplo:

public class Tuple < E > {

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

}

Ou você pode usar uma 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.
}

As sugestões para manter uma referência ao tipo de E com um objeto Class parecem ineficiente (que é um monte de referências inúteis para um Class ocupando memória) e inútil para o seu problema.

Não é geralmente verdade que Foo<Bar> andFoo<Baz> deve ser desigual. Então você não precisa E. E, no código que você escreveu, você nem precisa dele para compilar. Simplesmente lançar a Tuple<?>, uma vez que é realmente tudo o que você sabe sobre Tuple naquele ponto. Ele ainda compila e tudo.

Se você são passados ??Tuples com dados de dois tipos muito diferentes, esses elementos não será equals, e seu método retornará false, como desejado. (Espera-se -. Depende desses tipos de aplicação equals sanely)

Off-topic - você percebe que de acordo com a sua implementação, Tuple (a0, a1) é igual a Tuple (a1, a1)? Eu suspeito que não é o que você quer ...

On-tema, como já foi dito, o apagamento torna isso impossível. Mas você deveria reconsiderar porque você quer isso - a igualdade de verificação só acontece em tempo de execução, e genéricos são apenas em tempo de compilação . Conceitualmente, um variável tem parâmetros genéricos, mas um objeto não. Assim, quando você está comparando a igualdade de objetos, os parâmetros genéricos não importa a todos; você não pode tomar as medidas adequadas com base neles em tempo de execução de qualquer maneira.

igualdade Object, e genérico parâmetro co / contra-variância, são duas preocupações ortogonais.

Concordo com os comentários acima, por que o E necessidade classe para ser igual? e como você quer subclasses tratar de E?

De qualquer forma, já que aqui é um exemplo de código que podem ajudá-lo:

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

Você pode chamar t.getClass () para obter informações de classe sobre o tipo de T (assumindo que não é nulo, é claro.)

Espero que isso ajude.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top